diff --git a/framework/include/multiapps/TransientMultiApp.h b/framework/include/multiapps/TransientMultiApp.h index ba0d570e59c4..bd798af96f12 100644 --- a/framework/include/multiapps/TransientMultiApp.h +++ b/framework/include/multiapps/TransientMultiApp.h @@ -50,6 +50,8 @@ class TransientMultiApp : private: std::vector _transient_executioners; + + bool _sub_cycling; }; #endif // TRANSIENTMULTIAPP_H diff --git a/framework/src/multiapps/TransientMultiApp.C b/framework/src/multiapps/TransientMultiApp.C index 2e1dc2f09c17..89976ed260af 100644 --- a/framework/src/multiapps/TransientMultiApp.C +++ b/framework/src/multiapps/TransientMultiApp.C @@ -23,13 +23,17 @@ InputParameters validParams() { InputParameters params = validParams(); params += validParams(); + + params.addParam("sub_cycling", false, "Set to true to allow this MultiApp to take smaller timesteps than the rest of the simulation. More than one timestep will be performed for each 'master' timestep"); + return params; } TransientMultiApp::TransientMultiApp(const std::string & name, InputParameters parameters): MultiApp(name, parameters), - TransientInterface(parameters, name, "multiapps") + TransientInterface(parameters, name, "multiapps"), + _sub_cycling(getParam("sub_cycling")) { if(!_has_an_app) return; @@ -91,10 +95,44 @@ TransientMultiApp::solveStep() for(unsigned int i=0; i<_my_num_apps; i++) { Transient * ex = _transient_executioners[i]; - ex->takeStep(_dt); - if(!ex->lastSolveConverged()) - mooseWarning(_name<<_first_local_app+i<<" failed to converge!"<endStep(); + + if(_sub_cycling) + { + // Get the dt this app wants to take + Real dt = ex->computeConstrainedDT(); + + // Divide the "master" dt by that + Real partial_steps = _dt / dt; + + unsigned int num_steps = 0; + + if(partial_steps-std::floor(partial_steps) <= 2.0e-14) + num_steps = std::floor(partial_steps); + else + num_steps = std::ceil(partial_steps); + + // Split the master dt up into the number of steps (so we can hit the time perfectly) + dt = _dt / (Real)num_steps; + + // Now do all of the solves we need + for(unsigned int i=0; itakeStep(dt); + + if(!ex->lastSolveConverged()) + mooseWarning("While sub_cycling "<<_name<<_first_local_app+i<<" failed to converge!"<endStep(); + } + } + else + { + ex->takeStep(_dt); + + if(!ex->lastSolveConverged()) + mooseWarning(_name<<_first_local_app+i<<" failed to converge!"<endStep(); + } } // Swap back @@ -106,6 +144,9 @@ TransientMultiApp::solveStep() Real TransientMultiApp::computeDT() { + if(_sub_cycling) // Bow out of the timestep selection dance + return std::numeric_limits::max(); + Real smallest_dt = std::numeric_limits::max(); if(_has_an_app) diff --git a/test/tests/multiapps/sub_cycling/gold/master_out.e b/test/tests/multiapps/sub_cycling/gold/master_out.e new file mode 100644 index 000000000000..805e99ee6390 Binary files /dev/null and b/test/tests/multiapps/sub_cycling/gold/master_out.e differ diff --git a/test/tests/multiapps/sub_cycling/gold/master_out_sub0.e b/test/tests/multiapps/sub_cycling/gold/master_out_sub0.e new file mode 100644 index 000000000000..a4243ad6df5f Binary files /dev/null and b/test/tests/multiapps/sub_cycling/gold/master_out_sub0.e differ diff --git a/test/tests/multiapps/sub_cycling/master.i b/test/tests/multiapps/sub_cycling/master.i new file mode 100644 index 000000000000..02066ce30f4c --- /dev/null +++ b/test/tests/multiapps/sub_cycling/master.i @@ -0,0 +1,64 @@ +[Mesh] + type = GeneratedMesh + dim = 2 + nx = 10 + ny = 10 +[] + +[Variables] + [./u] + [../] +[] + +[Kernels] + [./diff] + type = Diffusion + variable = u + [../] + [./td] + type = TimeDerivative + variable = u + [../] +[] + +[BCs] + [./left] + type = DirichletBC + variable = u + boundary = left + value = 0 + [../] + [./right] + type = DirichletBC + variable = u + boundary = right + value = 1 + [../] +[] + +[Executioner] + type = Transient + num_steps = 4 + dt = 0.1 + petsc_options = '-snes_mf_operator -ksp_monitor' + petsc_options_iname = '-pc_type -pc_hypre_type' + petsc_options_value = 'hypre boomeramg' +[] + +[Output] + output_initial = true + exodus = true + perf_log = true +[] + +[MultiApps] + [./sub] + type = TransientMultiApp + app_type = MooseTestApp + execute_on = timestep + positions = '0 0 0' + input_files = sub.i + sub_cycling = true + [../] +[] + diff --git a/test/tests/multiapps/sub_cycling/sub.i b/test/tests/multiapps/sub_cycling/sub.i new file mode 100644 index 000000000000..d601667d4400 --- /dev/null +++ b/test/tests/multiapps/sub_cycling/sub.i @@ -0,0 +1,53 @@ +[Mesh] + type = GeneratedMesh + dim = 2 + nx = 10 + ny = 10 +[] + +[Variables] + [./u] + [../] +[] + +[Kernels] + [./diff] + type = Diffusion + variable = u + [../] + [./td] + type = TimeDerivative + variable = u + [../] +[] + +[BCs] + [./left] + type = DirichletBC + variable = u + boundary = left + value = 0 + [../] + [./right] + type = DirichletBC + variable = u + boundary = right + value = 1 + [../] +[] + +[Executioner] + type = Transient + num_steps = 4 + dt = 0.01 + petsc_options = '-snes_mf_operator -ksp_monitor' + petsc_options_iname = '-pc_type -pc_hypre_type' + petsc_options_value = 'hypre boomeramg' +[] + +[Output] + output_initial = true + exodus = true + perf_log = true +[] + diff --git a/test/tests/multiapps/sub_cycling/tests b/test/tests/multiapps/sub_cycling/tests new file mode 100644 index 000000000000..fb83c6a9be35 --- /dev/null +++ b/test/tests/multiapps/sub_cycling/tests @@ -0,0 +1,7 @@ +[Tests] + [./test] + type = 'Exodiff' + input = 'master.i' + exodiff = 'master_out.e master_out_sub0.e' + [../] +[]