int main(int argc, char **args) {
  /*----------------------Initialize MPI--------------------------------------*/
  PetscMPIInt rank, size;
  char programDescription[] = "Two pipe simulation";
  MPIGuard mpiGuard(&argc, &args, programDescription, &rank, &size);
  /*----------------Parameter configuration-----------------------------------*/
  // command line options
  PetscBool optionFlag;
  PetscInt intR, intTortuosity, intRadiusContrast;
  PetscScalar R0, tortuosity, radiusContrast;
  PetscOptionsGetInt(nullptr, "-initialRadius", &intR, &optionFlag);
  if (optionFlag == PETSC_FALSE)
    throw std::runtime_error("The initial radius must be specified.");
  R0 = intR*1e-9;
  PetscOptionsGetInt(nullptr, "-tortuosity", &intTortuosity, &optionFlag);
  if (optionFlag == PETSC_FALSE)
    throw std::runtime_error("The tortuosity must be specified.");
  tortuosity = intTortuosity/1000.0;
  PetscOptionsGetInt(nullptr, "-radiusContrast", &intRadiusContrast, &optionFlag);
  if (optionFlag == PETSC_FALSE)
    throw std::runtime_error("The radius contrast must be specified in the two pipe model");
  radiusContrast = intRadiusContrast/10.0;
  char directory[100];
  PetscOptionsGetString(nullptr, "-directory", directory,
                        sizeof(directory), &optionFlag);
  if (optionFlag == PETSC_FALSE)
    throw std::runtime_error("The output directory must be specified.");
  std::string prefix1 = std::string(directory) + std::string("r_")
                     + std::to_string(intR) + std::string("_t_")
                     + std::to_string(intTortuosity) + std::string("_c_")
                     + std::to_string(intRadiusContrast);
  prefix1.push_back('_');
  if (optionFlag == PETSC_FALSE)
    throw std::runtime_error("The pressure outputfile must be specified.");
  PetscInt numberOfPipes;  // spatial resolution
  PetscOptionsGetInt(nullptr, "-numberOfPipes", &numberOfPipes, &optionFlag);
  if (optionFlag == PETSC_FALSE)
    throw std::runtime_error("The number of pipes must be specified.");
  PetscInt numberOfSteps;  // maximum number of computation steps
  PetscOptionsGetInt(nullptr, "-numberOfSteps", &numberOfSteps, &optionFlag);
  if (optionFlag == PETSC_FALSE)
    throw std::runtime_error("The number of steps must be specified.");
  PetscInt hoursToSimulate;
  PetscOptionsGetInt(nullptr, "-hoursToSimulate", &hoursToSimulate, &optionFlag);
  if (optionFlag == PETSC_FALSE)
    throw std::runtime_error("The hours of simulation must be specified.");
  PetscScalar duration = hoursToSimulate * 3600.0;
  // tunable parameters (all in SI units)
  const PetscScalar totalFlux = 1.31e-9; // total flux
  const PetscScalar p1 = 2e6;  // initial upstream pressure 
  const PetscScalar initialConcentration = 35.0; 
  const PetscScalar C0 = 0.0;  // upstream concentration
  const PetscScalar sampleLength = 2.62e-2;  // sample length
  const PetscInt recordFrequency = 1000;
  // input parameters
  InputParameters ip;
  ip.nu = 9.0e-7;  // kinetic viscosity
  ip.D_m = 7.9e-10;  // molecular diffusivity
  ip.L = sampleLength*tortuosity/numberOfPipes;  // pipe Length
  ip.eta = 1.07e-3;  // viscosity
  ip.P_0 = 1e5;  // reference pressure
  ip.Sh_inf = 3.66;  // Sherwood constant
  ip.C_S = 35.0;  // solubility
  ip.k_S = 1.87e-3/ip.C_S;  // reactive constant
  ip.M = 100.0e-3;  // molar mass of CaCO3
  ip.rho = 2.7e3;  // density of CaCO3
  ip.update_derived_parameters();
  PetscScalar flux0 = M_PI*ip.L*ip.L*ip.L*ip.P_0/8/ip.eta;
  if (rank == size-1)
    ip.print_all_paparemters();
  /*----------------------Construct all unknown vectors-----------------------*/
  int global_n = numberOfPipes;
  int step = (global_n-1)/size+1;
  int local_n = rank < size-1 ? step : (global_n - step*(size-1));
  if (local_n <= 0)
    throw std::runtime_error(
        "Problem sizes is smaller than the number of threads.");
  int local_offset = rank*step*sizeof(PetscScalar);
  int global_offset = global_n*sizeof(PetscScalar);
  UniqueVec radii1(local_n, global_n);
  UniqueVec concentration1(local_n, global_n);
  UniqueVec radii2(local_n, global_n);
  UniqueVec concentration2(local_n, global_n);
  PaddedInitializer<UniformInitializer> concentration_initializer(
      UniformInitializer(initialConcentration/ip.C_S), rank, 0.0);
  concentration_initializer.padding_initialize(0/*no padding*/, concentration1);
  concentration_initializer.padding_initialize(0/*no padding*/, concentration2);
  {
    PaddedInitializer<UniformInitializer> radii_initializer1(
        UniformInitializer(R0/ip.L), rank, 0.0);
    radii_initializer1.padding_initialize(0/*no padding*/, radii1);
    PaddedInitializer<UniformInitializer> radii_initializer2(
        UniformInitializer(R0/ip.L/radiusContrast), rank, 0.0);
    radii_initializer2.padding_initialize(0/*no padding*/, radii2);
  }
  /*------------------------Initialize the coupled simulator------------------*/
  PetscScalar maxTime = duration/ip.T_0;
  std::string prefix2("/nobackup1/haoyue/NotImplemented");
  TwoPipeSimulation simulator(global_n, local_n, global_offset, local_offset,
      rank, size, ip, C0, flux0,
      radii1, concentration1, prefix1, radii2, concentration2, prefix2,
      maxTime, numberOfSteps, recordFrequency, totalFlux, p1); 
  simulator.doStepping();
  return 0;
}
int main(int argc, char **args) {
  /*----------------------Initialize MPI--------------------------------------*/
  PetscMPIInt rank, size;
  char programDescription[] = "Coupled simulation";
  MPIGuard mpiGuard(&argc, &args, programDescription, &rank, &size);
  /*----------------Parameter configuration-----------------------------------*/
  // command line options
  std::cout << "*****************************" << std::endl; 
  PetscBool optionFlag;
  PetscInt intR, intTortuosity;
  PetscScalar R0, tortuosity;
  intR = 3200;
  R0 = intR*1e-9;
  intTortuosity = 1000;
  tortuosity = intTortuosity/1000.0;
  char directory[100] = "/nobackup1/haoyue/";
  std::string prefix = std::string(directory) + std::string("r_")
                     + std::to_string(intR) + std::string("_t_")
                     + std::to_string(intTortuosity);
  std::cout << "hahahahah" << directory << std::endl; 
  prefix.push_back('_');
  PetscInt numberOfPipes = 100;  // spatial resolution
  PetscInt numberOfSteps;  // maximum number of computation steps
  PetscOptionsGetInt(nullptr, "-numberOfSteps", &numberOfSteps, &optionFlag);
  if (optionFlag == PETSC_FALSE)
    throw std::runtime_error("The number of steps must be specified.");
  // tunable parameters (all in SI units)
  const PetscScalar totalFlux = 1.31e-9; // total flux
  const PetscScalar p1 = 2e6;  // initial upstream pressure 
  const PetscScalar duration = 8*3600;  // experiment duration
  const PetscScalar initialConcentration = 35.0; 
  const PetscScalar C0 = 0.0;  // upstream concentration
  const PetscScalar sampleLength = 2.62e-2;  // sample length
  const PetscInt recordFrequency = 1000;
  // input parameters
  InputParameters ip;
  ip.nu = 9.0e-7;  // kinetic viscosity
  ip.D_m = 7.9e-10;  // molecular diffusivity
  ip.L = sampleLength*tortuosity/numberOfPipes;  // pipe Length
  ip.eta = 1.07e-3;  // viscosity
  ip.P_0 = 1e5;  // reference pressure
  ip.Sh_inf = 3.66;  // Sherwood constant
  ip.C_S = 35.0;  // solubility
  ip.k_S = 1.87e-3/ip.C_S;  // reactive constant
  ip.M = 100.0e-3;  // molar mass of CaCO3
  ip.rho = 2.7e3;  // density of CaCO3
  ip.update_derived_parameters();
  PetscScalar flux0 = M_PI*ip.L*ip.L*ip.L*ip.P_0/8/ip.eta;
  if (rank == size-1)
    ip.print_all_paparemters();
  /*----------------------Construct all unknown vectors-----------------------*/
  int global_n = numberOfPipes;
  int step = (global_n-1)/size+1;
  int local_n = rank < size-1 ? step : (global_n - step*(size-1));
  if (local_n <= 0)
    throw std::runtime_error(
        "Problem sizes is smaller than the number of threads.");
  int local_offset = rank*step*sizeof(PetscScalar);
  int global_offset = global_n*sizeof(PetscScalar);
  UniqueVec radii(local_n, global_n);
  UniqueVec concentration(local_n, global_n);
  PaddedInitializer<UniformInitializer> concentration_initializer(
      UniformInitializer(initialConcentration/ip.C_S), rank, 0.0);
  concentration_initializer.padding_initialize(0/*no padding*/, concentration);
  PaddedInitializer<UniformInitializer> radii_initializer(
      UniformInitializer(R0/ip.L), rank, 0.0);
  radii_initializer.padding_initialize(0/*no padding*/, radii);
  /*------------------------Initialize the coupled simulator------------------*/
  PetscScalar maxTime = duration/ip.T_0;
  OnePipeSimulation simulator(global_n, local_n, global_offset, local_offset,
      rank, size, ip, C0, flux0, radii, concentration, prefix, maxTime,
      numberOfSteps, recordFrequency, totalFlux, p1); 
  simulator.doStepping();
  simulator.checkMassBalance();
  return 0;
}