Hello Chrono,
After this post <https://groups.google.com/g/projectchrono/c/of58DygfuAA>, 
I've actually sat down to implement AmgX in chrono. It seems easier than I 
thought... Or at least I think.

This is `Setup` from solver:

```
bool ChSolverAmgX::Setup(ChSystemDescriptor& sysd) {
    // code assuming one AmgX per machine although it may well not be in 
the case of multiple instances of Chrono
    // running in paralel
    AMGX_SAFE_CALL(AMGX_initialize());
    // also can be created from a string. You know solvers better, so 
config up to you.
    AMGX_SAFE_CALL(AMGX_config_create_from_file(&cfg, "path_to_config_here"
))

    AMGX_resources_create_simple(&rsrc, cfg);
    AMGX_matrix_create(&A, rsrc, mode);  // the code seems to never create 
the matrices first.
    AMGX_vector_create(&x, rsrc, mode);
    AMGX_vector_create(&b, rsrc, mode);
    AMGX_solver_create(&solver, rsrc, mode, cfg);

    // sysd.WriteMatrixMtx("where_to_read_matrix_from.", "prefix_sample_", 
true);
    // AMGX_read_system(A, b, x, "prefix_sample_.mtx");// this is if we 
want store and read file.

    ChSparseMatrix Z;
    sysd.BuildSystemMatrix(&Z, &m_rhs);
    AMGX_matrix_upload_all(A, Z., Z.nonZeros(), Z.outerSize(), Z.innerSize(), 
Z.outerIndexPtr(), Z.innerIndexPtr(),
                           &Z.data(),
                           Z.diagonal().data());  // I'm not dead sure 
about block_dimx, block_dimy...

    AMGX_solver_setup(solver, A);  // bulk of the matrix setup

    return true;
} ``` The AMGX_matrix_upload_all command is basically to put chrono vectors 
of data to amgx. So it needs that data for solution. It requires `n`, 
`block_dimx` and `block_dimy` parameters: [image: image (4).png]

I don't 100% know how solvers work on the inside, so where can I take these 
values? I understand that these values are arising from bodies and 
constraints, but I'm not 100% sure. What do I need to input there? 
Cheers, Maksym Riabov P.S. I'll add the two files that serve as logic, so 
you may take a look - maybe you'd say something.

-- 
You received this message because you are subscribed to the Google Groups 
"ProjectChrono" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/projectchrono/f120fba4-b8ae-459b-8782-3b029c149ccdn%40googlegroups.com.
#include "chrono/solver/ChIterativeSolver.h"
#include "chrono/solver/ChSolverAmgX.h"
#include "amgx_c.h"
#include <Eigen/Dense>

namespace chrono {

bool ChSolverAmgX::Setup(ChSystemDescriptor& sysd) {
    // code assuming one AmgX per machine although it may well not be in the case of multiple instances of Chrono
    // running in paralel
    AMGX_SAFE_CALL(AMGX_initialize());
    // also can be created from a string. You know solvers better.
    AMGX_SAFE_CALL(AMGX_config_create_from_file(&cfg, "path_to_config_here"))

    AMGX_resources_create_simple(&rsrc, cfg);
    AMGX_matrix_create(&A, rsrc, mode);  // the code seems to never create the matrices first.
    AMGX_vector_create(&x, rsrc, mode);
    AMGX_vector_create(&b, rsrc, mode);
    AMGX_solver_create(&solver, rsrc, mode, cfg);

    // sysd.WriteMatrixMtx("where_to_read_matrix_from.", "prefix_sample_", true); // this is if we want to read it.
    // AMGX_read_system(A, b, x, "prefix_sample_.mtx");

    ChSparseMatrix Z;
    sysd.BuildSystemMatrix(&Z, &m_rhs);
    AMGX_matrix_upload_all(A, Z., Z.nonZeros(), Z.outerSize(), Z.innerSize(), Z.outerIndexPtr(), Z.innerIndexPtr(),
                           &Z.data(),
                           Z.diagonal().data());  // I'm not dead sure about block_dimx, block_dimy...

    AMGX_solver_setup(solver, A);  // bulk of the matrix setup

    return true;
}

double ChSolverAmgX::Solve(ChSystemDescriptor& sysd) {
    // Assemble the problem right-hand side vector
    // sysd.BuildSystemMatrix(nullptr, &m_rhs); // why?

    AMGX_solver_solve(solver, b, x);
    AMGX_solver_get_status(solver, &status);

    // download the solution from AmgX to chrono
    AMGX_vector_download(x, &m_sol);

    //  if successful
    // if (status == AMGX_SOLVE_SUCCESS)
    //     //???

    // destroy // chrono: May be unnecessary. What do you think?
    AMGX_solver_destroy(solver);
    AMGX_vector_destroy(x);
    AMGX_vector_destroy(b);
    AMGX_matrix_destroy(A);
    AMGX_resources_destroy(rsrc);

    // probably too early to destroy config; it will be reused among iterations, unless you
    // want to shut AmgX down completely..
    // AMGX_SAFE_CALL(AMGX_config_destroy(cfg)); //<- better add this to chrono final cleanup.
}  // namespace chrono
}  // namespace chrono
//--
#include "chrono/solver/ChIterativeSolver.h"
#include "chrono/solver/ChSolver.h"

namespace chrono {

class ChApi ChSolverAmgX : public ChIterativeSolver, ChSolver {
  public:
    virtual ~ChSolverAmgX();

    /// Perform the solver setup operations.\n
    /// Here, sysd is the system description with constraints and variables.
    /// Returns true if successful and false otherwise.
    virtual bool Setup(ChSystemDescriptor& sysd) override;

    /// Performs the solution of the problem.\n
    /// Return the maximum constraint violation after termination.
    virtual double Solve(ChSystemDescriptor& sysd) override;

  protected:
    ChSolverAmgX();

    virtual ChIterativeSolver* AsIterative() override { return this; }

    /// Indicate whether or not the #Solve() phase requires an up-to-date problem matrix.
    virtual bool SolveRequiresMatrix() const override final { return true; }

    /// Initialize the solver with the current sparse matrix and return true if successful.
    virtual bool SetupProblem() = 0;

    /// Solve the linear system using the current factorization and right-hand side vector.
    /// Load the solution vector (already of appropriate size) and return true if succesful.
    virtual bool SolveProblem() = 0;

    // to make variables reusable w/o changing API... setup+solve was in a single function before.
    //--- AMGX ---
    // AmgX versions //mriabov: if needed. Unused here.
    int major, minor;
    char *ver, *date, *time;
    // input geometry //mriabov: if needed. Unused here.
    double* gx = NULL;
    double* gy = NULL;
    double* gz = NULL;
    // input coloring //mriabov: if needed. Unused here.
    int dim = 0;
    int numrows = 0;
    int num_colors = 0;
    int colored_rows = 0;
    int* row_coloring = NULL;
    // input matrix and rhs/solution
    int n = 0;
    int bsize_x = 0;
    int bsize_y = 0;
    int sol_size = 0;
    int sol_bsize = 0;
    // library handles

    // Mode by letters: d:compute on device (vs h: compute on host), D: use double
    // precision for local(chrono) types, D: use double precision for computation, I:
    // use types as int32 (is always as int32.) So, this mode is compute on device, use double. *CAN BE CHANGED!* (See
    // line https://github.com/NVIDIA/AMGX/blob/main/examples/amgx_capi.c, line 243)
    // Note: AmgX can also compute on host, and I'd suspect it's efficient too. So, todo integrate on CPU.
    AMGX_Mode mode = AMGX_Mode::AMGX_mode_dDDI;

    AMGX_resources_handle rsrc;
    AMGX_matrix_handle A;
    AMGX_vector_handle b, x;
    AMGX_solver_handle solver;
    // status handling
    AMGX_SOLVE_STATUS status;

    // --- Chrono ---
    ChVectorDynamic<double> m_sol;  ///< solution vector
    ChVectorDynamic<double> m_rhs;  ///< right-hand side vector
    // ChVectorDynamic<double> m_invdiag;    ///< inverse diagonal entries (for preconditioning)
    // ChVectorDynamic<double> m_initguess;  ///< initial guess (for warm start)
};
};  // namespace chrono

Reply via email to