// Variables that are defined at the “top level” (typically in ALL CAPS) are not
// actually read in directly, but instead are used to define various values for
// input settings for specific components (e.g. CartesianGridGeometry,
// IBHierarchyIntegrator, etc.) below.
//
// I put these at the top level mostly for user convenience, but also because
// some of them wind up getting used in a few different places.
//
// Some of these values are "derived" values, not input parameters per se; these
// are marked by [derived].
//
// Boolean values can take only "TRUE" or "FALSE".
//
// Numerical values written in floating point notation take real values; other
// numerical values are generally integers.

// physical parameters
MU  = 0.01                                          // dynamic viscosity of the fluid; any non-negative real value (including zero)
RHO = 1.0                                           // mass density of the fluid; any non-negative real value  (including zero)
L   = 1.0                                           // “basic” length of the computational domain (for a square domain; the domain is not necessarily square; this could be changed to L_x, L_y, etc.)

// grid spacing parameters
MAX_LEVELS = 1                                      // maximum number of levels in locally refined grid (any positive integer value)
REF_RATIO  = 2                                      // refinement ratio between levels (any positive integer value, but 2 or 4 is recommended; other values are not well tested in general)
N = 64                                              // "basic" number of grid cells on coarsest grid level (assuming a square domain; see note above for L)
NFINEST = (REF_RATIO^(MAX_LEVELS - 1))*N            // [derived] effective number of grid cells on finest grid level (this would be the number of grid cells on the finest level if the grid was uniformly refined)
DX0 = L/N                                           // [derived] Cartesian mesh width on coarsest grid level
DX  = L/NFINEST                                     // [derived] Cartesian width on finest grid level
MFAC = 2.0                                          // ratio of structural mesh width to Cartesian mesh width (positive real number; this is only used in examples where the code generates the structural mesh "on the fly")
ELEM_TYPE = "TRI6"                                  // type of element to use for structure discretization (in 2D: "TRI3", "TRI6", "QUAD4", "QUAD8", "QUAD9"; in 3D: "TET3", "TET10", "HEX8", "HEX20", "HEX27"; this is only used in examples where the code generates the structural mesh "on the fly")
PK1_DEV_QUAD_ORDER = "FIFTH"                        // quadrature rule order for the "deviatoric" part of the stress ("CONSTANT", "FIRST", "SECOND", "THIRD", ..., "FOURTYTHIRD"; see: https://libmesh.github.io/doxygen/namespacelibMesh.html#a147df8c2f5821ede7626f9ed907e0634)
PK1_DIL_QUAD_ORDER = "THIRD"                        // quadrature rule for the "dilational" part of the stress (see note above)

// model parameters
U_MAX = 2.0                                         // maximum velocity estimate; this is used to set the time step size
C1_S = 0.05                                         // neo-Hookean stiffness parameter (non-negative real number)
P0_S = C1_S                                         // stress pressure normalization parameter (non-negative real number)
BETA_S = 1.0*(NFINEST/64.0)                         // bulk modulus parameter (non-negative real number)

// solver parameters
IB_DELTA_FUNCTION          = "IB_4"                 // the type of smoothed delta function to use for Lagrangian-Eulerian interaction ("IB_3", "IB_4", "IB_6", "PIECEWISE_LINEAR", "PIECEWISE_CUBIC", "BSPLINE_3", "BSPLINE_4", "BSPLINE_5", "BSPLINE_6", ...)
SPLIT_FORCES               = FALSE                  // whether to split interior and boundary forces
USE_JUMP_CONDITIONS        = FALSE                  // whether to impose pressure jumps at fluid-structure interfaces
USE_CONSISTENT_MASS_MATRIX = TRUE                   // whether to use a consistent or lumped mass matrix
IB_POINT_DENSITY           = 3.0                    // approximate density of IB quadrature points for Lagrangian-Eulerian interaction (positive real value)
SOLVER_TYPE                = "STAGGERED"            // the fluid solver to use ("STAGGERED" or "COLLOCATED"; "STAGGERED" is recommended)
START_TIME                 = 0.0e0                  // initial simulation time (real value)
END_TIME                   = 10.0                   // final simulation time (real value > START_TIME)
GROW_DT                    = 2.0e0                  // growth factor for timesteps (real value >= 1.0)
NUM_CYCLES                 = 1                      // number of cycles of fixed-point iteration (integer >= 1)
CONVECTIVE_TS_TYPE         = "ADAMS_BASHFORTH"      // convective time stepping type ("ADAMS_BASHFORTH", "FOWARD_EULER", "MIDPOINT_RULE", "TRAPEZOIDAL_RULE"; midpoint and trapezoidal rules require NUM_CYCLES >= 2)
CONVECTIVE_OP_TYPE         = "PPM"                  // convective differencing discretization type ("PPM" or "CENTERED")
CONVECTIVE_FORM            = "ADVECTIVE"            // how to compute the convective terms ("ADVECTIVE", "CONSERVAITVE", or "SKEW_SYMMETRIC")
NORMALIZE_PRESSURE         = FALSE                  // whether to explicitly force the pressure to have mean zero
CFL_MAX                    = 0.25                   // maximum CFL number (positive real number, recommended <= 0.5)
DT                         = 0.25*CFL_MAX*DX/U_MAX  // [derived] maximum timestep size
ERROR_ON_DT_CHANGE         = TRUE                   // whether to emit an error message if the time step size changes
VORTICITY_TAGGING          = TRUE                   // whether to tag cells for refinement based on vorticity thresholds
TAG_BUFFER                 = 1                      // size of tag buffer used by grid generation algorithm (non-negative integer)
REGRID_CFL_INTERVAL        = 0.5                    // regrid whenever any material point could have moved 0.5 meshwidths since previous regrid (non-negative real)
OUTPUT_U                   = TRUE                   // whether to output the velocity field
OUTPUT_P                   = TRUE                   // whether to output the pressure field
OUTPUT_F                   = TRUE                   // whether to output the body force field
OUTPUT_OMEGA               = TRUE                   // whether to output the vorticity field
OUTPUT_DIV_U               = TRUE                   // whether to output the computed divergence of the velocity field
ENABLE_LOGGING             = TRUE

// collocated solver parameters
PROJECTION_METHOD_TYPE = "PRESSURE_UPDATE"          // choices are "PRESSURE_INCREMENT" or "PRESSURE_UPDATE"
SECOND_ORDER_PRESSURE_UPDATE = TRUE

// The next two blocks specify boundary conditions in a form like:
//
//    a*u + b*du/dn = g
//
// as explicit functions of position and time.
//
// The subscripts indicate which side of the domain: 0 = lower x, 1 = upper x, 2 = lower y, 3 = upper y, etc.
VelocityBcCoefs_0 {
   acoef_function_0 = "1.0"
   acoef_function_1 = "1.0"
   acoef_function_2 = "1.0"
   acoef_function_3 = "1.0"

   bcoef_function_0 = "0.0"
   bcoef_function_1 = "0.0"
   bcoef_function_2 = "0.0"
   bcoef_function_3 = "0.0"

   gcoef_function_0 = "0.0"
   gcoef_function_1 = "0.0"
   gcoef_function_2 = "0.0"
   gcoef_function_3 = "1.0"
}

VelocityBcCoefs_1 {
   acoef_function_0 = "1.0"
   acoef_function_1 = "1.0"
   acoef_function_2 = "1.0"
   acoef_function_3 = "1.0"

   bcoef_function_0 = "0.0"
   bcoef_function_1 = "0.0"
   bcoef_function_2 = "0.0"
   bcoef_function_3 = "0.0"

   gcoef_function_0 = "0.0"
   gcoef_function_1 = "0.0"
   gcoef_function_2 = "0.0"
   gcoef_function_3 = "0.0"
}

// Notice that all of these values are really defined above.
IBHierarchyIntegrator {
   start_time          = START_TIME
   end_time            = END_TIME
   grow_dt             = GROW_DT
   num_cycles          = NUM_CYCLES
   regrid_cfl_interval = REGRID_CFL_INTERVAL
   dt_max              = DT
   error_on_dt_change  = ERROR_ON_DT_CHANGE
   enable_logging      = ENABLE_LOGGING
}

IBFEMethod {
   IB_delta_fcn               = IB_DELTA_FUNCTION
   split_forces               = SPLIT_FORCES
   use_jump_conditions        = USE_JUMP_CONDITIONS
   use_consistent_mass_matrix = USE_CONSISTENT_MASS_MATRIX
   IB_point_density           = IB_POINT_DENSITY
}

INSCollocatedHierarchyIntegrator {
   mu                            = MU
   rho                           = RHO
   start_time                    = START_TIME
   end_time                      = END_TIME
   grow_dt                       = GROW_DT
   convective_time_stepping_type = CONVECTIVE_TS_TYPE
   convective_op_type            = CONVECTIVE_OP_TYPE
   convective_difference_form    = CONVECTIVE_FORM
   normalize_pressure            = NORMALIZE_PRESSURE
   cfl                           = CFL_MAX
   dt_max                        = DT
   using_vorticity_tagging       = VORTICITY_TAGGING
   vorticity_rel_thresh          = 0.01                // this is a feature detection criterion used in generating AMR grids; it can actually be an array of values (e.g. "vorticity_rel_thresh = 0.1, 0.2, 0.3" would define a threshold of 0.1 on level 0, 0.2 on level 1, and 0.3 on level 2 and all finer levels)
   tag_buffer                    = TAG_BUFFER          // this could be an array of integer values, one for each level, but here it is set to the same integer value for all levels
   output_U                      = OUTPUT_U
   output_P                      = OUTPUT_P
   output_F                      = OUTPUT_F
   output_Omega                  = OUTPUT_OMEGA
   output_Div_U                  = OUTPUT_DIV_U
   enable_logging                = ENABLE_LOGGING
   projection_method_type        = PROJECTION_METHOD_TYPE
   use_2nd_order_pressure_update = SECOND_ORDER_PRESSURE_UPDATE
}

INSStaggeredHierarchyIntegrator {
   mu                            = MU
   rho                           = RHO
   start_time                    = START_TIME
   end_time                      = END_TIME
   grow_dt                       = GROW_DT
   convective_time_stepping_type = CONVECTIVE_TS_TYPE
   convective_op_type            = CONVECTIVE_OP_TYPE
   convective_difference_form    = CONVECTIVE_FORM
   normalize_pressure            = NORMALIZE_PRESSURE
   cfl                           = CFL_MAX
   dt_max                        = DT
   using_vorticity_tagging       = VORTICITY_TAGGING
   vorticity_rel_thresh          = 0.01
   tag_buffer                    = TAG_BUFFER
   output_U                      = OUTPUT_U
   output_P                      = OUTPUT_P
   output_F                      = OUTPUT_F
   output_Omega                  = OUTPUT_OMEGA
   output_Div_U                  = OUTPUT_DIV_U
   enable_logging                = ENABLE_LOGGING
}

Main {
   solver_type = SOLVER_TYPE

// log file parameters
   log_file_name               = "IB2d.log"
   log_all_nodes               = FALSE

// visualization dump parameters
   viz_writer                  = "VisIt","ExodusII"    // options are "VisIt", "ExodusII", "Silo"
   viz_dump_interval           = int(0.125/DT)         // integer value, zero to turn off
   viz_dump_dirname            = "viz_IB2d"
   visit_number_procs_per_file = 1

// restart dump parameters
   restart_dump_interval       = 0                     // integer value, zero to turn off
   restart_dump_dirname        = "restart_IB2d"

// hierarchy data dump parameters
   data_dump_interval          = 0                     // integer value, zero to turn off
   data_dump_dirname           = "hier_data_IB2d"

// timer dump parameters
   timer_dump_interval         = 0                     // integer value, zero to turn off, probably not worth including as this functionality should be going away soon
}

CartesianGeometry {
   domain_boxes = [ (0,0),(N - 1,N - 1) ]              // the cell-centered indices of the lower-left and upper-right corners of the computational domain on the coarsest level; any integer values would work as long as they are correctly oriented (e.g. the "upper" corner really has to be "above and to the right" of the "lower" corner)
   x_lo = 0,0                                          // the physical location of the lower left corner, any pair of real values (but (0,0) is the most well tested)
   x_up = L,L                                          // the physical locaiton of the upper right corner, any pair of real values so long as x_lo(i) < x_up(i) for i=0,1,...
   periodic_dimension = 0,0                            // array of integers that are *really* booleans, indicating whether a particular coordinate direction should be treated as periodic (1) or not (0).
}

GriddingAlgorithm {
   max_levels = MAX_LEVELS
   ratio_to_coarser {
      level_1 = REF_RATIO,REF_RATIO                    // refinement ratio between level 0 and level 1, there could be different ratios in the different coordinate directions, but we usually use the same ratio in all directions
      level_2 = REF_RATIO,REF_RATIO
      level_3 = REF_RATIO,REF_RATIO
      level_4 = REF_RATIO,REF_RATIO
      level_5 = REF_RATIO,REF_RATIO                    // refinement ratio between level 5 and level 4, as well as for any finer levels (e.g. for level n and level n-1 for n >= 5)
   }
   largest_patch_size {
      level_0 = 512,512  // pair of positive integers (this can be set level-by-level; here, all levels will use same values as level_0)
   }
   smallest_patch_size {
      level_0 =   8,  8  // pair of positive integers (this can be set level-by-level; here, all levels will use same values as level_0)
   }
   efficiency_tolerance = 0.85e0  // min % of tag cells in new patch level (real number between 0 and 1)
   combine_efficiency   = 0.85e0  // chop box if sum of volumes of smaller boxes < efficiency * vol of large box (real number between 0 and 1)
}

StandardTagAndInitialize {
   tagging_method = "GRADIENT_DETECTOR"  // "GRADIENT_DETECTOR" (this really means "feature detection") or "REFINE_BOXES" --- if "REFINE_BOXES" is set, there is extra stuff that needs to go here listing the boxes to refine on each level
}

LoadBalancer {
   bin_pack_method     = "SPATIAL"      // we only use "SPATIAL" presently
   max_workload_factor = 1              // we only use "1" presently
}

// This functionality should go away soon:
TimerManager {
   print_exclusive = FALSE
   print_total     = TRUE
   print_threshold = 0.1
   timer_list      = "IBAMR::*::*","IBTK::*::*","*::*::*"
}
