/* 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 #include #include #include #include namespace aspect { namespace InitialTemperature { template PlateCooling::AsciiData () {} template void PlateCooling::initialize () { const std::set boundary_ids = this->get_fixed_temperature_boundary_indicators(); Utilities::AsciiDataBoundary::initialize(boundary_ids, 1); } template void PlateCooling::update () { Interface::update (); Utilities::AsciiDataBoundary::update(); } template double PlateCooling::initial_temperature (const types::boundary_id boundary_indicator, const Point &position) const { double age_top = Utilities::AsciiDataBoundary::get_data_component(boundary_indicator, position, 0); // return age_top; //} //template //double //PlateCooling:: //initial_temperature (const Point &position) const //{ // convert input ages to seconds //const double age_top = (this->convert_output_to_years() ? age_top_boundary_layer * year_in_seconds // : age_top_boundary_layer); // 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->get_boundary_temperature_manager().minimal_temperature(this->get_fixed_temperature_boundary_indicators()); const double T_bottom = this->get_boundary_temperature_manager().maximal_temperature(this->get_fixed_temperature_boundary_indicators()); // get a representative profile of the compositional fields as an input // for the material model 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()); in.position[0]=position; in.temperature[0]=this->get_adiabatic_conditions().temperature(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.strain_rate.resize(0); // adiabat has strain=0. 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]) ); // analytical solution for the thermal boundary layer from half-space cooling model if (this->get_geometry_model().depth(position) > zlo) { const double temperature_profile = T_bottom; return temperature_profile; } else { const double pi = 3.1415; const double exp_fac = -kappa * std::pow(pi, 2) * age_top / std::pow(zlo, 2); const double sin_fac = pi / zlo; unsigned int n = 1; double sum_terms = 0; while (n <= m) { sum_terms += 1/(double)n * std::exp(std::pow((double)n, 2) * exp_fac) * std::sin((double)n * (this->get_geometry_model().depth(position) * sin_fac)); n += 1; } const double temperature_profile = T_surface + (T_bottom - T_surface) * ((this->get_geometry_model().depth(position)) / zlo + 2/pi * sum_terms); return temperature_profile; } } template void PlateCooling::declare_parameters (ParameterHandler &prm) { prm.enter_subsection ("Initial temperature model"); { Utilities::AsciiDataBoundary::declare_parameters(prm, "$ASPECT_SOURCE_DIR/data/boundary-temperature/ascii-data/test/", "box_2d_%s.%d.txt"); prm.enter_subsection("Plate cooling"); { 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 ("Depth to plate base", "125.e3", Patterns::Anything (), "The depth to the base of the plate. Units: m"); prm.declare_entry ("Number of terms in sum", "5", Patterns::Integer (1), "The number of terms to include in the summation"); //Utilities::AsciiDataBoundary::declare_parameters(prm, // "$ASPECT_SOURCE_DIR/data/boundary-temperature/ascii-data/test/", // "box_2d_%s.%d.txt"); prm.enter_subsection("Function"); { Functions::ParsedFunction<1>::declare_parameters (prm, 1); } prm.leave_subsection(); } prm.leave_subsection (); } prm.leave_subsection (); } template void PlateCooling::parse_parameters (ParameterHandler &prm) { // 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::AsciiDataBoundary::parse_parameters(prm); prm.enter_subsection("Plate cooling"); { age_top_boundary_layer = prm.get_double ("Age top boundary layer"); zlo = prm.get_double ("Depth to plate base"); m = prm.get_integer ("Number of terms in sum"); //Utilities::AsciiDataBoundary::parse_parameters(prm); if (n_compositional_fields > 0) { prm.enter_subsection("Function"); try { function = std_cxx14::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.leave_subsection (); } prm.leave_subsection (); } } } // explicit instantiations namespace aspect { namespace InitialTemperature { ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(PlateCooling, "plate cooling", "Temperature is prescribed as a plate cooling model " "profile with upper and lower thermal boundary layers, " "whose ages are given as input parameters.") } }