Quick Start Guide

The goal of this page is to get the reader started as quickly as possible using Chronos. This page is meant as a guide through downloading the binary, installing the library, and testing the installation.

How to get Chronos

Chronos can be obtained by contacting the developer team by sending a request to the e-mail: products@m3eweb.it or fill the lower form at Chronos webpage to get the Chronos DISTRO.

To correctly install Chronos, specific information about the target machine is required. The request must include the following details:

  • the processor model and architecture;
  • the version of GNU compiler;
  • the operating system;
  • the OpenMPI version;
  • the OpenSSL version;

The developer team will take care of the request and will provide the proper package fitting the machine’s features along with all the necessary for the license activation.

Installation

Chronos’s requirements for the installation are:

  • CMake 3.0.0 or later
  • GNU 7.5.0 or later
  • OpenMPI 3.1 or later
  • OpenMP 4.0 or later

The procedure for the installation consists of two steps, i.e., the license activation and the driver installation.

License activation

The first step is the license activation that can be carried out in two ways:

  1. Online: the machine where Chronos runs must be connect to at least one machine with a Internet connection, which will be the License Server;
  2. Offline: the machine where Chronos runs does not need to be connect to Internet.

Online
In this case, along with the DISTRO package, the user will also be provided the license key, the product data and the executable of the On-Premising Floating License Server, a closed software used to handle licensing provided by CRYPTLEX.

The user has to select a host with an Internet connection. On this host, to start the licensing service the user must run the following command with administrator privileges:

./lexfloatserver -s -p pruduct.dat

The executable can be found in the directory FloatServer (provided by the developer team). We suggest running this service as daemon since, for each Chronos run, a request is sent to the server asking about license information, available tokens, and so on.

After checking in the log file, which can be found in the directory /logs, that the service started up correctly; the user can move to the license activation. A browser must be opened connecting to http://locahost:8090, a log in screen will appear. The default login credentials are available in the configuration file.
Once logged in the user will see a dashboard. The reader must go to settings and copy the provided licence key in the approriate box. Once done, click on “Activate” and wait for the licence activation.

If the procedure was successful, the last step before running Chronos is setting the environment variable CHRONOS_FLOATSERVER_IP which sets the IP of the host where the license server is running:

export CHRONOS_FLOATSERVER_IP="http://ip_licensing_host:8090"

This environment variable must be defined in the script used to lunch Chronos or in the program which calls Chronos.

Offline
If the machine where Chronos needs to run does not have an Internet connection, one must follow this procedure. The user needs to run the following program, provided in the FloatServer directory, to compute the fingerprint of the machine:

./cptFingerprint 

This script generates a file (fingerprint.dat) containing the fingerprint and other information necessary for the license activation. The user has to send the developers this file and will receive back the token associated to the license. After the user receives the token, the last step consists of running the following script (provided with the FloatServer directory) in order to complete the activation:

./installToken <token-file>

Where to run this token is irrelevant to the installation of the token.

Driver installation

The second step consists of compiling the driver contained in the DISTRO package. Depending on the preferences of the user the CPU only driver or the CPU and GPU driver can be used whether one needs to use only CPUs or also GPUs. If one eventually will need to use also GPUs can skip this first part and go directly to the CPU+GPU part.

CPU only Driver
To start compiling the driver, the user needs to move inside the following directory:

cd Drivers/Minimal_Driver.cpp

Then run “make” in this directory. If everything works fine an executable called chronos_shell will be generated.

CPU+GPU Driver
To start compiling the driver, the user needs to move inside the following directory:

cd Drivers/Minimal_Driver.cu

Then run “make” in this directory. If everything works fine an executable called chronos_shell will be generated.

Now the user can move on to the next section and test the installation with the first run.

First Run

Some examples showing how to solve a linear system by using the methods implemented in Chronos have been added. After working through these examples, the user should have a good understanding of how to set up and solve a linear system.

The DISTRO package is provided with a sample driver, whose sources is accessible by users in “Drivers/Minimal_Driver.cpp/driver.cpp”, with the purpose to explain the use of the library: chronos_shell.

Chronos_shell reads the matrix, the test space and RHS from binary files. The source of the Chronos_shell is provided here, but parts have been commented to make the read simpler and shorter:

/* 
    ..... include headers and libraries
*/

//----------------------------------------------------------------------------------------

int main(int argc,char **argv){

   // --- MPI initialization -------------------------------------------------------------
   type_MPI_int mpisupport,rank,size;

   type_MPI_int ierr = MPI_Init_thread(&argc,&argv,MPI_THREAD_FUNNELED,&mpisupport);
   if(ierr != 0) throw mpi_error("driver","MPI_Init_thread","Unknown");
   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
   MPI_Comm_size(MPI_COMM_WORLD,&size);

   // --- Init Chronos -------------------------------------------------------------------
   if (!Chronos.init()){
      cout << "Error in Chronos initialization" << endl;
      MPI_Barrier(MPI_COMM_WORLD);
      MPI_Finalize();
   }

   if(rank==0){cout << endl << "MPI Initialization done" << endl;}


   // --- Read elaboration parameters ----------------------------------------------------

   if(rank==0){cout<< endl << "- Read elaboration parameters"<<endl<<endl;}

   // Open input files
   ifstream input_fnames;
   input_fnames.open(argv[1]);
   string Matrix_fname, RHS_fname, TestSpace_fname, XML_fname;
   bool USE_aFSAI = false;
   bool PRINT_SOL = false;
   bool PRINT_RHS = false;
   bool PRINT_MAT = false;
   int RHS_Flag = 1;

   input_fnames >> Matrix_fname;    next_line(input_fnames);
   input_fnames >> RHS_fname;       next_line(input_fnames);
   input_fnames >> TestSpace_fname; next_line(input_fnames);
   input_fnames >> XML_fname;       next_line(input_fnames);
   input_fnames >> USE_aFSAI;       next_line(input_fnames);
   input_fnames >> RHS_Flag;        next_line(input_fnames);
   input_fnames >> PRINT_SOL;       next_line(input_fnames);
   input_fnames >> PRINT_RHS;       next_line(input_fnames);
   input_fnames >> PRINT_MAT;       next_line(input_fnames);
   input_fnames.close();

   // Check RHS flag
   if (RHS_Flag < 0 || RHS_Flag > 3)
      throw linsol_error("Driver","Wrong value of RHS_Flag");

   // Read the XML configuration file
   xml_document Chronos_xml_config;
   try {
      Chronos_xml_config = read_XML_config(XML_fname);
   } catch (linsol_error) {
      linsol_error("Driver_METIS","Error while reading XML input");
      MPI_Finalize();
      return 1;
   }

   // Read and set general parameters from XML
   int verbosity;
   bool PART_flag, RCM_flag, BC_flag, TIMINGS_flag;
   try {
      verbosity = get_verbosity_XML(Chronos_xml_config);
      PART_flag = get_PART_flag_XML(Chronos_xml_config);
      RCM_flag = get_RCM_flag_XML(Chronos_xml_config);
      BC_flag = get_BC_flag_XML(Chronos_xml_config);
      TIMINGS_flag = get_TIMINGS_flag_XML(Chronos_xml_config);
   } catch (linsol_error) {
      linsol_error("Driver_METIS","Error while reading general parameters from XML");
      MPI_Finalize();
      return 1;
   }

   // --- Open Log file ------------------------------------------------------------------
   FILE *logfile;
   if (rank == 0) logfile = fopen("CHRONOS.log","w");

   // --- Dump elaboration parameters ----------------------------------------------------
   /*
        ..... 
    */

   // --- Set-up of the Library Environment ----------------------------------------------
   Chronos.Set_inpNthreads();
   Chronos.Set_Verbosity(verbosity);
   Chronos.Set_GetTime(TIMINGS_flag);

   // +++ TRUE execution SCOPE +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   {

   // --- Get Input ----------------------------------------------------------------------
   if(rank==0){cout << endl << "Get Matrix" << endl;}

   // --- Parallel read of the input matrix ----------------------------------------------
   /*
        ..... 
    */

   // --- Treat Boundary conditions ------------------------------------------------------
   /*
        ..... 
    */

   // --- Read the Test Space ------------------------------------------------------------
   /*
        ..... 
    */

   // --- Create the RHS -----------------------------------------------------------------
   /*
        ..... Computing or importing RHS
    */

   // --- Partition with parMETIS --------------------------------------------------------
   /*
        ..... Partitioning Matrix, RHS and test space if parMETIS licence available
    */

   // --- Compute local permutation ------------------------------------------------------
   /*
        ..... Compute and apply RCM permutation
    */

   // --- aFSAI Computation --------------------------------------------------------------

   // creates the object
   aFSAI_CPU PREC_aFSAI;

   rExt aFSAI_Time = 0.;
   rExt aAMG_Time  = 0.;

   // Check Preconditioner Type
   if ( USE_aFSAI ) {

      if(rank==0){cout << endl << "aFSAI Computation" << endl;}
      MPI_Barrier(MPI_COMM_WORLD);

      if (MEMORY_STAT_DUMP) Chronos.PrintMemInfo(nullptr);

      // set aFSAI parameters
      PREC_aFSAI.Set_default();
      PREC_aFSAI.SetParms_from_XML(Chronos_xml_config);
      PREC_aFSAI.DumpAllParms(nullptr);

      //-----------------------------
      // Start timing              //
      MPI_Barrier(MPI_COMM_WORLD); //
      rExt T_start = MPI_Wtime();  //
      //-----------------------------

      // compute aFSAI
      try {
         PREC_aFSAI.Compute(*mat_APR);
      } catch (linsol_error) {
         MPI_Finalize();
      }

      //------------------------------------
      // Get time for aFSAI Computation   //
      MPI_Barrier(MPI_COMM_WORLD);        //
      aFSAI_Time = MPI_Wtime() - T_start; //
      //------------------------------------

      if (MEMORY_STAT_DUMP) Chronos.PrintMemInfo(nullptr);

      MPI_Barrier(MPI_COMM_WORLD);

   }

   // --- aAMG Computation ---------------------------------------------------------------

   // Creates the object
   aAMG PREC_aAMG;

   // Check Preconditioner Type
   if ( !USE_aFSAI ) {

      if(rank==0){cout << endl << "aAMG Computation" << endl;}
      MPI_Barrier(MPI_COMM_WORLD);

      // set aAMG parameters
      PREC_aAMG.SetParms_from_XML(Chronos_xml_config);
      PREC_aAMG.DumpAllParms(nullptr);

      //-----------------------------
      // Start timing              //
      MPI_Barrier(MPI_COMM_WORLD); //
      rExt T_start = MPI_Wtime();  //
      //-----------------------------

      // compute aAMG
      try {
         PREC_aAMG.Compute(*mat_APR,TV0_PR);
      } catch (linsol_error) {
         MPI_Finalize();
      }

      //-----------------------------------
      // Get time for aAMG computation   //
      MPI_Barrier(MPI_COMM_WORLD);       //
      aAMG_Time = MPI_Wtime() - T_start; //
      //-----------------------------------

      MPI_Barrier(MPI_COMM_WORLD);

   }

   // --- Print PRECONDITIONER info ------------------------------------------------------
   /*
        .....
    */

   // --- Solver -------------------------------------------------------------------------

   // Creates the object
   LinSolver *SOLVER;

   // Choose between PCG, GMRES, BiCGstab or SQMR
   if (Chronos_xml_config.child("Chronos").child("lin-solver").child("PCG")){
      // PCG
      SOLVER = new PCG_CPU();
      if(rank==0) cout << endl << "PCG Solver" << endl;
   } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("BICGSTAB")){
      // BiCGstab
      SOLVER = new BiCGstab_CPU();
      if(rank==0) cout << endl << "BiCGstab Solver" << endl;
   } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("GMRES")){
      // GMRES
      SOLVER = new GMRES_CPU();
      if(rank==0) cout << endl << "GMRES Solver" << endl;
   } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("SQMR")){
      // SQMR
      SOLVER = new SQMR_CPU();
      if(rank==0) cout << endl << "SQMR Solver" << endl;
   } else {
      if(rank==0) cout << endl << "Solver NOT specified" << endl;
      MPI_Finalize();
      return 0;
   }
   MPI_Barrier(MPI_COMM_WORLD);

   // Sets user parameters
   SOLVER->SetParms_from_XML(Chronos_xml_config);

   // Sets the linear solver
   if(rank==0){cout << "- set solver" << endl;}
   MPI_Barrier(MPI_COMM_WORLD);

   //-----------------------------
   // Start timing              //
   MPI_Barrier(MPI_COMM_WORLD); //
   rExt T_start = MPI_Wtime();  //
   //-----------------------------

   // Declare a dummy preconditioner
   IDMat dummy_PREC = IDMat(mat_APR->get_nrows());

   try{
      if (USE_aFSAI){
         if (Chronos_xml_config.child("Chronos").child("lin-solver").child("PCG")){
            // PCG
            SOLVER->Set_Solver(*mat_APR,*RHS_PR,PREC_aFSAI);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("BICGSTAB")){
            // BiCGstab
            SOLVER->Set_Solver(*mat_APR,*RHS_PR,dummy_PREC,PREC_aFSAI);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("GMRES")){
            // GMRES
            SOLVER->Set_Solver(*mat_APR,*RHS_PR,dummy_PREC,PREC_aFSAI);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("SQMR")){
            // SQMR
            SOLVER->Set_Solver(*mat_APR,*RHS_PR,PREC_aFSAI,dummy_PREC);
         }
      } else {
         if (Chronos_xml_config.child("Chronos").child("lin-solver").child("PCG")){
            // PCG
            SOLVER->Set_Solver(*mat_APR,*RHS_PR,PREC_aAMG);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("BICGSTAB")){
            // BiCGstab
            SOLVER->Set_Solver(*mat_APR,*RHS_PR,dummy_PREC,PREC_aAMG);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("GMRES")){
            // GMRES
            SOLVER->Set_Solver(*mat_APR,*RHS_PR,dummy_PREC,PREC_aAMG);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("SQMR")){
            // SQMR
            SOLVER->Set_Solver(*mat_APR,*RHS_PR,PREC_aAMG,dummy_PREC);
         }
      }
   } catch (linsol_error) {
      MPI_Finalize();
   }

   //-------------------------------------------
   // Get time for SOL Setting                //
   MPI_Barrier(MPI_COMM_WORLD);               //
   rExt SOL_Set_Time = MPI_Wtime() - T_start; //
   //-------------------------------------------

   // Solve the system
   if(rank==0){cout << "- solve" << endl;}
   MPI_Barrier(MPI_COMM_WORLD);

   //-----------------------------
   // Start timing              //
   MPI_Barrier(MPI_COMM_WORLD); //
   T_start = MPI_Wtime();       //
   //-----------------------------

   try{
      if (USE_aFSAI){
         string ConvProf = "./OUT/aFSAI_SOL_conv_profile";
         if (Chronos_xml_config.child("Chronos").child("lin-solver").child("PCG")){
            // PCG
            SOLVER->Solve(*mat_APR,*RHS_PR,SOL_PR,PREC_aFSAI,&ConvProf);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("BICGSTAB")){
            // BiCGstab
            SOLVER->Solve(*mat_APR,*RHS_PR,SOL_PR,dummy_PREC,PREC_aFSAI,&ConvProf);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("GMRES")){
            // GMRES
            SOLVER->Solve(*mat_APR,*RHS_PR,SOL_PR,dummy_PREC,PREC_aFSAI,&ConvProf);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("SQMR")){
            // SQMR
            SOLVER->Solve(*mat_APR,*RHS_PR,SOL_PR,PREC_aFSAI,dummy_PREC,&ConvProf);
         }
      } else {
         string ConvProf = "./OUT/aAMG_SOL_conv_profile";
         if (Chronos_xml_config.child("Chronos").child("lin-solver").child("PCG")){
            // PCG
            SOLVER->Solve(*mat_APR,*RHS_PR,SOL_PR,PREC_aAMG,&ConvProf);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("BICGSTAB")){
            // BiCGstab
            SOLVER->Solve(*mat_APR,*RHS_PR,SOL_PR,dummy_PREC,PREC_aAMG,&ConvProf);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("GMRES")){
            // GMRES
            SOLVER->Solve(*mat_APR,*RHS_PR,SOL_PR,PREC_aAMG,&ConvProf);
         } else if (Chronos_xml_config.child("Chronos").child("lin-solver").child("SQMR")){
            // SQMR
            SOLVER->Solve(*mat_APR,*RHS_PR,SOL_PR,PREC_aAMG,&ConvProf);
         }
      }
   } catch (linsol_error) {
      MPI_Finalize();
   }

   //-------------------------------------------
   // Get time for the Solver                 //
   MPI_Barrier(MPI_COMM_WORLD);               //
   rExt Solver_Time = MPI_Wtime() - T_start; //
   //-------------------------------------------

   MPI_Barrier(MPI_COMM_WORLD);

   // --- Permute back the solution ------------------------------------------------------
   /*
        .....
    */

   // --- Repartition back the solution --------------------------------------------------
   /*
        .....
    */

   // --- Compute the error --------------------------------------------------------------

   rExt normERR[nRHS];
   if ( RHS_Flag == 0 || RHS_Flag == 2){
      rExt normSOL[nRHS];
      rExt reduc[nRHS];
      rExt* ptr_Ref_Sol = Ref_Sol.get_ptr_coef_data();
      rExt* ptr_Sol = SOL.get_ptr_coef_data();
      iReg k = 0;
      for (iReg i = 0; i < my_nrows; i++){
         for (iReg j = 0; j < nRHS; j++){
            ptr_Ref_Sol[k] -= ptr_Sol[k];
            k++;
         }
      }
      dnrm2_par(0,1,my_nrows,nRHS,ptr_Ref_Sol,nRHS,reduc,normERR);
      dnrm2_par(0,1,my_nrows,nRHS,ptr_Sol,nRHS,reduc,normSOL);
      for (iReg j = 0; j < nRHS; j++) normERR[j] /= normSOL[j];
   }

   // --- Print PRECONDITIONER info ------------------------------------------------------
   /*
        .....
    */

   // --- Print Set-Up and Solve times ---------------------------------------------------
   /*
        .....
    */

   // --- Compute real residual in the driver --------------------------------------------

   my_nrows = mat_APR->get_nrows();
   DDMat_CPU RES;
   RES.resize(my_nrows,nRHS);
   VEC_CPU<rExt> nones(nRHS,-1.);
   VEC_CPU<rExt> vec_REALRES(nRHS);
   try {
      mat_APR->Prepare_MxV(nRHS);
      mat_APR->MxV(SOL_PR, RES, true);
      RES.dxpay(nones,*RHS_PR);
      RES.nrm2(vec_REALRES);
   } catch (linsol_error) {
      throw linsol_error("Driver_METIS","error in computing real residual");
   }

   // --- print ITER and normRHS for each RHS --------------------------------------------
   /*
        ..... Print results and delete Objects
    */


   // --- Close Log file -----------------------------------------------------------------
   if (rank == 0) fclose(logfile);

   }

   // --- Finalize Chronos -------------------------------------------------------------------
   // --- MPI Finalize -------------------------------------------------------------------
   /*
        .....
    */
   return 0;
}

The drivers requires the fnames file as a command-line input (As in example RUN executable inside the benchmark directory), i.e., the user should invoke the drivers as:

mpirun -np k ./chronos_shell fnames_<>

where k is the number of MPI ranks required for the run and fnames_<> is the file containing the location of matrix, rhs, test space and configuration XML file as well as some other important information. In addition to the MPI parallelization, Chronos offers shared memory parallelism through openMP. Setting the number of threads is possible through the environment variable OMP_NUM_THREADS.
A sample fnames file is shown below:

./Cubo_35199.csr.Ext_Bin                //Input matrix
./None                                  //Input RHS
./Cubo_35199.rbm.Ext_Bin                //Input Test space
./Chronos_AMG_config.xml                //Input Configuration file
0                                       //USE_aFSAI (0 --> False, 1 --> True)
0                                       //RHS_Flag (0--> unit sol, 1--> unit rhs, 2--> rand sol, 3--> ext rhs)
0                                       //PRINT_SOL (0=F)
0                                       //PRINT_RHS (0=F)
0                                       //PRINT_MAT (0=F)

In the fnames file the user must include the matrix file name, the test space file name and their location, as well as the following:

  • _config.xml the configuration file for the preconditioner, can be either Chronos_AMG_config.xml or Chronos_FSAI_config.xml;
  • USE_aFSAI, bool, sets whether to use aFSAI as a preconditioner;
  • RHS_Flag, integer, sets how to treat the RHS:
    • 0, sets the RHS such that the solution is unitary;
    • 1, sets the RHS to be unitary;
    • 2, sets the RHS to be equal to the matrix multiplied by a random vector;
    • 3, sets the RHS to an external input, need to have specified the location of the file in the Input RHS.
  • PRINT_SOL, bool, sets if to print the solution;
  • PRINT_RHS, bool, sets if to print the rhs;
  • PRINT_MAT, bool, sets if to print the matrix.

An example of Chronos_AMG_config.xml for a mechanical problem is as follows:

<Chronos>

<!--  GENERAL SET-UP PARAMETERS -->
  <general-parms 
    verbosity="2"
    PART_flag="true"
    RCM_flag="false"
    BC_flag="false"
    TIMINGS_flag="true"/>

<!--  PRECONDITIONER SET-UP PARAMETERS -->
  <preconditioner>

    <AMG
      maxnlevel="10"
      maxcoarsesize="1000"

      tspace_ntv="6"
      tspace_maxiter="100"

      smooth_type="1"
      smooth_nstep="15"
      smooth_step_size="1"
      smooth_eps="1.e-3"

      coars_type="0"
      coars_tau="-30.0"

      prolo_type="0"
      prolo_smoothemin="2"

    />

  </preconditioner>

<!--  SOLVER SET-UP PARAMETERS -->
  <lin-solver>
    <PCG
      maxiter="5000"
      tolerance="1e-08"
      init_sol="0"
      profile_PRT="true"
    />
  </lin-solver>

</Chronos>

The tag Chronos is always required to have the driver work properly and must enclose all the other tags.
The other tags that need to be specified inside Chronos are the following:

  1. general-parms: it is used to set the parameters affecting the whole library with the keywords:

    • verbosity, necessary integer, the verbosity level \(\in [0,3]\);
    • PART_flag, necessary bool, for matrix partitioning through metis;
    • RCM_flag, necessary bool, for matrix local reordering with RCM;
    • BC_flag, necessary bool, sets whether to try to fix eventual ill posed Dirichlet boundary conditions;
    • TIMINGS_flag, necessary bool, sets if to save and print the timings of the different sections;
  2. preconditioner: this tag specifies the preconditioner used in the iterative process. The user must specify one and only one of the following, mutually exclusive, keywords:

    • aFSAI, to use the adaptive FSAI preconditioner, which allows the following sub-keywords:
      • nstep, optional integer, indicating the number of steps used to build aFSAI (default 15);
      • step_size, optional integer, indicating the number of entries added for each row at each step of the adaptive procedure (default 1);
      • eps, optional real, exit tolerance used in the adaptive procedure (default \(10^{-3}\));

    Note that tuning aFSAI with the sub-keywords can be very helpfull. As a rule-of-thumb, the product between steps and step_size controls the preconditioner density (i.e., the number of non-zeros), with larger values leading to a more accurate but expensive preconditioner. In a similar way, smaller values for epsilon lead to a more accurate but expensive preconditioner.

    • AMG, to use an AMG preconditioner, allowing the following sub-keywords:
      • maxnlevel, optional integer, defines the maximum number of levels for the cycle (default 20);
      • maxcoarsesize, optional integer, defines the maximum size of the coarsest grid (default 500);
      • tspace_ntv, optional integer, defines the number of eigenvectors making up the test space (default 6);
      • tspace_maxiter, optional integer, defines the maximum number of iterations to find the eigenvectors (default 20);
      • smooth_type, optional integer, defines whether to use (0) Jacobi or (1) aFSAI as a smoother for AMG (default 1);
      • smooth_nstep, optional integer, indicating the number of steps used to build aFSAI (default 15);
      • smooth_step_size, optional integer, indicating the number of entries added for each row at each step of the adaptive procedure (default 1);
      • smooth_eps, optional real, exit tolerance used in the adaptive procedure (default \(10^{-3}\));
      • coars_type, optional integer, defines which coarsening algorithm to use (default 0);
        • 0, Diagonally Dominant;
        • 1, Classical;
        • 2, Affinity Based (can be used only if test space is available);
      • coars_tau, optional real, selects the SoC filtering threshold (default -40.0);
      • prolo_type, optional integer, defines which prolongation type to use (default 0):
        • 0, BAMG;
        • 1, EXTI;
        • 2, CLASSICAL;
        • 3, HYBRID (exti+class);
        • 4, EXTI_MxM;
      • prolo_smoothemin, defines which smoothing to apply to the prolongation: (0) none, (1) simple smoothing, (2) energy minimization (default 2).
  3. solver-parms: this tag specifies the parameters controlling the solver, which can be PCG, GMRES, SQMR or BiCGstab, and the following keywords can be set by the user:

    • maxiter, necessary integer, defines the maximum number of iterations;
    • tolerance, necessary real, defines the exit tolerance on the relative residual, \(\frac{\| b - A x_k\|}{\| b - A x_0\|}\);
    • init_sol, necessary integer, defines how the solution is initialized at the first iteration:
      • 0, sol0 = Prec x RHS;
      • 1, sol0 = 0;
      • 2, sol0 is given in input;
    • profile_PRT, necessary bool, determines whether the convergence profile is dumped during execution;
    • use_PrecRes, optional bool, determines whether to use or not the preconditioned residual;
    • restart, necessary integer, determines the number of iterations after which to restart the solver. If provided when not required, it is just ignored.

An example of AMG configuration file for a CFD case follows:

<Chronos>

<!--  GENERAL SET-UP PARAMETERS -->
  <general-parms 
    verbosity="2"
    PART_flag="true"
    RCM_flag="false"
    BC_flag="false"
    TIMINGS_flag="true"/>

<!--  PRECONDITIONER SET-UP PARAMETERS -->
  <preconditioner>

    <AMG
      maxnlevel="10"
      maxcoarsesize="1000"

      smooth_type="1"
      smooth_nstep="15"
      smooth_step_size="1"
      smooth_eps="1.e-3"

      coars_type="1"
      coars_tau="0.25"

      prolo_type="2"
      prolo_smoothemin="0"

    />

  </preconditioner>

<!--  SOLVER SET-UP PARAMETERS -->
  <lin-solver>
    <PCG
      maxiter="5000"
      tolerance="1e-08"
      init_sol="0"
      profile_PRT="true"
    />
  </lin-solver>

</Chronos>

As it can be seen the only differences are that the parameters for the test space are missing and the values for the coarsening and prolongation have been modified.

The matrix is stored in coordinate format, with the first record containing the number of rows (the matrix is assumed to be square) and the number of non-zeros entries. Then, there is a record for each non-zero containing the row and column indices and the matrix entries. The matrix is stored row-wisely and the column indices of each row must be sorted as in the example below:

   1773       63927
     1            1   1.000000000000e+00
     2            2   1.000000000000e+00
     3            3   1.000000000000e+00
     4            4   1.000000000000e+00
     5            5   1.000000000000e+00
     6            6   1.000000000000e+00
     7            7   3.460330662810e+05
     7            9  -1.330896408773e+05
     7          329  -1.330896408773e+05
     7          330   5.323585635092e+04
     7          685  -5.323585635092e+04
     7          686   5.323585635092e+04
     7          687  -5.323585635092e+04
     7          688  -1.863254972282e+05
     7          689   7.985378452638e+04
     7          690   5.323585635092e+04
     7         1027  -1.064717127018e+05
     7         1029   7.985378452638e+04
     8            8   3.460330662810e+05
     8            9  -1.330896408773e+05
     8          328  -1.330896408773e+05
     .....

As to the test space, the first record contains the size of each test vector and the number of test vectors. Then, each record stores the components of all the test vectors as a rectangular skinny matrix. Below, an example of a test space represented by rigid body modes:

   1773          6
0.10000000E+01   0.00000000E+00   0.00000000E+00   0.00000000E+00  -0.50258597E+00   0.49504524E+00
0.00000000E+00   0.10000000E+01   0.00000000E+00   0.50258597E+00   0.00000000E+00  -0.49226410E+00
0.00000000E+00   0.00000000E+00   0.10000000E+01  -0.49504683E+00   0.49226126E+00   0.00000000E+00
0.10000000E+01   0.00000000E+00   0.00000000E+00   0.00000000E+00  -0.50258597E+00   0.49504524E+00
0.00000000E+00   0.10000000E+01   0.00000000E+00   0.50258597E+00   0.00000000E+00   0.50773590E+00
0.00000000E+00   0.00000000E+00   0.10000000E+01  -0.49504683E+00  -0.50773873E+00   0.00000000E+00
0.10000000E+01   0.00000000E+00   0.00000000E+00   0.00000000E+00  -0.50258597E+00  -0.50495476E+00
0.00000000E+00   0.10000000E+01   0.00000000E+00   0.50258597E+00   0.00000000E+00   0.50773590E+00
0.00000000E+00   0.00000000E+00   0.10000000E+01   0.50495316E+00  -0.50773873E+00   0.00000000E+00
.....

For a CFD problem the test space is substituted by the kernel of the matrix to be solved, so for example a poisson problem would have the test space to be the constant vector.

If the matrix and the test space files are in binary format, all the integers should be stored as long int and all reals as double. The datatype used by Chronos to store this information is set at the time of compilation, typically int for integers and double for reals. However, the datatype used in the input files does not depend upon the library setting: integers and reals are always read as long int and double, respectively, and are then converted internally to the appropriate data type. The RHS can be optionally read from file in exactly the same way as the test space.