// Clean deletes temporary data structures func (o *LinSolMumps) Clean() { // exit if not initialised if !o.is_initialised { return } // start time if o.ton { o.tini = time.Now() } // message if o.verb { io.Pfgreen("\n . . . . . . . . . . . . . . LinSolMumps.Clean . . . . . . . . . . . . . . . \n\n") } // clean up if o.cmplx { o.mz.job = -2 // finalize code C.zmumps_c(&o.mz) // do finalize } else { o.m.job = -2 // finalize code C.dmumps_c(&o.m) // do finalize } // duration if o.ton { io.Pfcyan("%s: Time spent in LinSolMumps.Clean = %v\n", o.name, time.Now().Sub(o.tini)) } }
// SolveC solves the linear Complex system A.x = b // NOTES: // 1) sum_b_to_root is a flag for MUMPS; it tells Solve to sum the values in 'b' arrays to the root processor func (o *LinSolMumps) SolveC(xR, xC, bR, bC []float64, sum_b_to_root bool) (err error) { // check if !o.cmplx { return chk.Err(_linsol_mumps_err11) } // start time if o.ton { o.tini = time.Now() } // message if o.verb { io.Pfgreen("\n . . . . . . . . . . . . . . LinSolMumps.SolveC . . . . . . . . . . . . . . . \n\n") } // MUMPS: set RHS in processor # 0 if sum_b_to_root { mpi.SumToRoot(xR, bR) mpi.SumToRoot(xC, bC) // join complex values if mpi.Rank() == 0 { for i := 0; i < len(xR); i++ { o.xRC[i*2], o.xRC[i*2+1] = xR[i], xC[i] } } } else { // join complex values if mpi.Rank() == 0 { for i := 0; i < len(xR); i++ { o.xRC[i*2], o.xRC[i*2+1] = bR[i], bC[i] } } } // MUMPS: solve o.mz.job = 3 // solution code C.zmumps_c(&o.mz) // solve if o.mz.info[1-1] < 0 { return chk.Err(_linsol_mumps_err12, mumps_error(o.mz.info[1-1], o.mz.info[2-1])) } // MUMPS: split complex values if mpi.Rank() == 0 { for i := 0; i < len(xR); i++ { xR[i], xC[i] = o.xRC[i*2], o.xRC[i*2+1] } } // MUMPS: broadcast from root mpi.BcastFromRoot(xR) mpi.BcastFromRoot(xC) // duration if o.ton { io.Pfcyan("%s: Time spent in LinSolMumps.Solve = %v\n", o.name, time.Now().Sub(o.tini)) } return }
// Fact performs symbolic/numeric factorisation. This method also converts the triplet form // to the column-compressed form, including the summation of duplicated entries func (o *LinSolMumps) Fact() (err error) { // check if !o.is_initialised { return chk.Err("linear solver must be initialised first\n") } // start time if o.ton { o.tini = time.Now() } // message if o.verb { io.Pfgreen("\n . . . . . . . . . . . . . . LinSolMumps.Fact . . . . . . . . . . . . . . . \n\n") } // complex if o.cmplx { // MUMPS: factorisation o.mz.job = 2 // factorisation code C.zmumps_c(&o.mz) // factorise if o.mz.info[1-1] < 0 { return chk.Err(_linsol_mumps_err08, "Real", mumps_error(o.mz.info[1-1], o.mz.info[2-1])) } // real } else { // MUMPS: factorisation o.m.job = 2 // factorisation code C.dmumps_c(&o.m) // factorise if o.m.info[1-1] < 0 { return chk.Err(_linsol_mumps_err08, "Complex", mumps_error(o.m.info[1-1], o.m.info[2-1])) } } // duration if o.ton { io.Pfcyan("%s: Time spent in LinSolMumps.Fact = %v\n", o.name, time.Now().Sub(o.tini)) } return }
// InitC initialises a LinSolMumps data structure for Complex systems. It also performs some initial analyses. func (o *LinSolMumps) InitC(tC *TripletC, symmetric, verbose, timing bool) (err error) { // check o.tC = tC if tC.pos == 0 { return chk.Err(_linsol_mumps_err04) } // flags o.name = "mumps" o.sym = symmetric o.cmplx = true o.verb = verbose o.ton = timing // start time if mpi.Rank() != 0 { o.verb = false o.ton = false } if o.ton { o.tini = time.Now() } // check xz if len(o.tC.xz) != 2*len(o.tC.i) { return chk.Err(_linsol_mumps_err05, len(o.tC.xz), len(o.tC.i)) } // initialise Mumps o.mz.comm_fortran = -987654 // use Fortran communicator by default o.mz.par = 1 // host also works o.mz.sym = 0 // 0=unsymmetric, 1=sym(pos-def), 2=symmetric(undef) if symmetric { o.mz.sym = 2 } o.mz.job = -1 // initialisation code C.zmumps_c(&o.mz) // initialise if o.mz.info[1-1] < 0 { return chk.Err(_linsol_mumps_err06, mumps_error(o.mz.info[1-1], o.mz.info[2-1])) } // convert indices to C.int (not C.long) and // increment indices since Mumps is 1-based (FORTRAN) o.mi, o.mj = make([]int32, o.tC.pos), make([]int32, o.tC.pos) for k := 0; k < tC.pos; k++ { o.mi[k] = int32(o.tC.i[k]) + 1 o.mj[k] = int32(o.tC.j[k]) + 1 } // set pointers o.mz.n = C.int(o.tC.m) o.mz.nz_loc = C.int(o.tC.pos) o.mz.irn_loc = (*C.int)(unsafe.Pointer(&o.mi[0])) o.mz.jcn_loc = (*C.int)(unsafe.Pointer(&o.mj[0])) o.mz.a_loc = (*C.ZMUMPS_COMPLEX)(unsafe.Pointer(&o.tC.xz[0])) // only proc # 0 needs the RHS if mpi.Rank() == 0 { o.xRC = make([]float64, 2*o.tC.n) o.mz.rhs = (*C.ZMUMPS_COMPLEX)(unsafe.Pointer(&o.xRC[0])) } // control if verbose { if mpi.Rank() == 0 { io.Pfgreen("\n . . . . . . . . . . . . . . LinSolMumps.InitC . . (MUMPS) . . . . . . . . . \n\n") } o.mz.icntl[1-1] = 6 // output stream for error messages o.mz.icntl[2-1] = 0 // output stream for statistics and warnings o.mz.icntl[3-1] = 6 // output stream for global information o.mz.icntl[4-1] = 2 // message level: 2==errors and warnings } else { o.mz.icntl[1-1] = -1 // no output messages o.mz.icntl[2-1] = -1 // no warnings o.mz.icntl[3-1] = -1 // no global information o.mz.icntl[4-1] = -1 // message level } o.mz.icntl[5-1] = 0 // assembled matrix (needed for distributed matrix) o.mz.icntl[6-1] = 7 // automatic (default) permuting strategy for diagonal terms o.mz.icntl[14-1] = 5000 // % increase of working space o.mz.icntl[18-1] = 3 // distributed matrix o.SetOrdScal("", "") // analysis step o.mz.job = 1 // analysis code C.zmumps_c(&o.mz) // analyse if o.mz.info[1-1] < 0 { return chk.Err(_linsol_mumps_err07, mumps_error(o.mz.info[1-1], o.mz.info[2-1])) } // duration if o.ton { io.Pfcyan("%s: Time spent in LinSolMumps.InitC = %v\n", o.name, time.Now().Sub(o.tini)) } // success o.is_initialised = true return }