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