class LinceseSolver(CeseSolver): """ Basic linear CESE solver. @ivar cfldt: the time_increment for CFL calculation at boundcond. @itype cfldt: float @ivar cflmax: the maximum CFL number. @itype cflmax: float """ from solvcon.dependency import getcdll __clib_lincese = { 2: getcdll('lincese2d', raise_on_fail=False), 3: getcdll('lincese3d', raise_on_fail=False), } del getcdll @property def _clib_lincese(self): return self.__clib_lincese[self.ndim] @property def _jacofunc_(self): return self._clib_lincese.calc_jaco def __init__(self, *args, **kw): self.cfldt = kw.pop('cfldt', None) self.cflmax = 0.0 super(LinceseSolver, self).__init__(*args, **kw) def make_grpda(self): raise NotImplementedError def provide(self): from ctypes import byref, c_int # fill group data array. self.make_grpda() # pre-calculate CFL. self._set_time(self.time, self.cfldt) self._clib_lincese.calc_cfl(byref(self.exd), c_int(0), c_int(self.ncell)) self.cflmax = self.cfl.max() # super method. super(LinceseSolver, self).provide() def calccfl(self, worker=None): self.marchret.setdefault('cfl', [0.0, 0.0, 0, 0]) self.marchret['cfl'][0] = self.cflmax self.marchret['cfl'][1] = self.cflmax self.marchret['cfl'][2] = 0 self.marchret['cfl'][3] = 0 return self.marchret
class EulerBC(CeseBC): """ Basic BC class for the Euler equations. """ from solvcon.dependency import getcdll __clib_eulerb = { 2: getcdll('eulerb2d', raise_on_fail=False), 3: getcdll('eulerb3d', raise_on_fail=False), } del getcdll @property def _clib_eulerb(self): return self.__clib_eulerb[self.svr.ndim]
class ElaslinBC(CeseBC): """ Basic BC class for elastic problems. """ from solvcon.dependency import getcdll __clib_elaslinb = { 2: getcdll('elaslinb2d', raise_on_fail=False), 3: getcdll('elaslinb3d', raise_on_fail=False), } del getcdll @property def _clib_elaslinb(self): return self.__clib_elaslinb[self.svr.ndim]
class NSBulkSolver(CuseSolver): """ Navier-Stokes solver based on the Bulk modulus. """ def __init__(self, blk, *args, **kw): kw['nsca'] = 12 super(NSBulkSolver, self).__init__(blk, *args, **kw) from solvcon.dependency import getcdll __clib_nsbulk_c = { 2: getcdll('nsbulk2d'), 3: getcdll('nsbulk3d'), } __clib_nsbulk_cu = { 2: getcdll('nsbulk2d_cu', raise_on_fail=False), 3: getcdll('nsbulk3d_cu', raise_on_fail=False), } del getcdll @property def _clib_nsbulk_c(self): return self.__clib_nsbulk_c[self.ndim] @property def _clib_nsbulk_cu(self): return self.__clib_nsbulk_cu[self.ndim] @property def _clib_mcu(self): return self.__clib_nsbulk_cu[self.ndim] _gdlen_ = 0 @property def _jacofunc_(self): return self._clib_nsbulk_c.calc_jaco @property def _viscfunc_(self): return self._clib_nsbulk_c.calc_viscous def calccfl(self, worker=None): from ctypes import byref if self.scu: self._clib_nsbulk_cu.calc_cfl(self.ncuth, byref(self.cumgr.exd), self.cumgr.gexd.gptr) else: self._clib_nsbulk_c.calc_cfl(byref(self.exd))
class LincuseSolver(CuseSolver): """ Basic linear CESE solver. @ivar cfldt: the time_increment for CFL calculation at boundcond. @itype cfldt: float @ivar cflmax: the maximum CFL number. @itype cflmax: float """ from solvcon.dependency import getcdll __clib_lincuse_c = { 2: getcdll('lincuse2d_c', raise_on_fail=False), 3: getcdll('lincuse3d_c', raise_on_fail=False), } __clib_lincuse_cu = { 2: getcdll('lincuse2d_cu', raise_on_fail=CUDA_RAISE_ON_FAIL), 3: getcdll('lincuse3d_cu', raise_on_fail=CUDA_RAISE_ON_FAIL), } del getcdll @property def _clib_lincuse_c(self): return self.__clib_lincuse_c[self.ndim] @property def _clib_lincuse_cu(self): return self.__clib_lincuse_cu[self.ndim] @property def _jacofunc_(self): return self._clib_lincuse_c.calc_jaco def __init__(self, *args, **kw): self.cfldt = kw.pop('cfldt', None) self.cflmax = 0.0 super(LincuseSolver, self).__init__(*args, **kw) def make_grpda(self): raise NotImplementedError def provide(self): from ctypes import byref, c_int # fill group data array. self.make_grpda() # pre-calculate CFL. self._set_time(self.time, self.cfldt) self._clib_lincuse_c.calc_cfl( byref(self.exd), c_int(0), c_int(self.ncell)) self.ocfl[:] = self.cfl[:] # super method. super(LincuseSolver, self).provide() def calccfl(self, worker=None): pass
class GasdynSolver(CuseSolver): """ Gas dynamics solver of the Euler equations. """ def __init__(self, blk, *args, **kw): kw['nsca'] = 1 super(GasdynSolver, self).__init__(blk, *args, **kw) from solvcon.dependency import getcdll __clib_gasdyn_c = { 2: getcdll('gasdyn2d_c', raise_on_fail=False), 3: getcdll('gasdyn3d_c', raise_on_fail=False), } __clib_gasdyn_cu = { 2: getcdll('gasdyn2d_cu', raise_on_fail=False), 3: getcdll('gasdyn3d_cu', raise_on_fail=False), } del getcdll @property def _clib_gasdyn_c(self): return self.__clib_gasdyn_c[self.ndim] @property def _clib_gasdyn_cu(self): return self.__clib_gasdyn_cu[self.ndim] @property def _clib_mcu(self): return self.__clib_gasdyn_cu[self.ndim] _gdlen_ = 0 @property def _jacofunc_(self): return self._clib_gasdyn_c.calc_jaco def calccfl(self, worker=None): from ctypes import byref if self.scu: self._clib_gasdyn_cu.calc_cfl(self.ncuth, byref(self.cumgr.exd), self.cumgr.gexd.gptr) else: self._clib_gasdyn_c.calc_cfl(byref(self.exd))
class NSBulkBC(CuseBC): """ Basic BC class for NS. """ from solvcon.dependency import getcdll __clib_nsbulkb_c = { 2: getcdll('nsbulkb2d'), 3: getcdll('nsbulkb3d'), } __clib_nsbulkb_cu = { 2: getcdll('nsbulkb2d_cu', raise_on_fail=False), 3: getcdll('nsbulkb3d_cu', raise_on_fail=False), } del getcdll @property def _clib_nsbulkb_c(self): return self.__clib_nsbulkb_c[self.svr.ndim] @property def _clib_nsbulkb_cu(self): return self.__clib_nsbulkb_cu[self.svr.ndim]
class EulerSolver(CeseSolver): """ Inviscid aerodynamic solver for the Euler equations. """ def __init__(self, blk, *args, **kw): self.cflname = kw.pop('cflname', 'adj') kw['nsca'] = 1 super(EulerSolver, self).__init__(blk, *args, **kw) self.cflc = self.cfl.copy() # FIXME: obselete? from solvcon.dependency import getcdll __clib_euler = { 2: getcdll('euler2d', raise_on_fail=False), 3: getcdll('euler3d', raise_on_fail=False), } del getcdll @property def _clib_euler(self): return self.__clib_euler[self.ndim] _gdlen_ = 0 @property def _jacofunc_(self): return self._clib_euler.calc_jaco def calccfl(self, worker=None): func = getattr(self._clib_euler, 'calc_cfl_' + self.cflname) self._tcall(func, 0, self.ncell) mincfl = self.ocfl.min() maxcfl = self.ocfl.max() nadj = (self.cfl == 1).sum() self.marchret.setdefault('cfl', [0.0, 0.0, 0, 0]) self.marchret['cfl'][0] = mincfl self.marchret['cfl'][1] = maxcfl self.marchret['cfl'][2] = nadj self.marchret['cfl'][3] += nadj return self.marchret
class GasdynBC(CuseBC): """ Basic BC class for gas dynamics. """ from solvcon.dependency import getcdll __clib_gasdynb_c = { 2: getcdll('gasdynb2d_c', raise_on_fail=False), 3: getcdll('gasdynb3d_c', raise_on_fail=False), } __clib_gasdynb_cu = { 2: getcdll('gasdynb2d_cu', raise_on_fail=False), 3: getcdll('gasdynb3d_cu', raise_on_fail=False), } del getcdll @property def _clib_gasdynb_c(self): return self.__clib_gasdynb_c[self.svr.ndim] @property def _clib_gasdynb_cu(self): return self.__clib_gasdynb_cu[self.svr.ndim]
class VslinBC(CuseBC): """ Basic BC class for elastic problems. """ from solvcon.dependency import getcdll __clib_vslinb_c = { 2: getcdll('vslinb2d_c', raise_on_fail=False), 3: getcdll('vslinb3d_c', raise_on_fail=False), } __clib_vslinb_cu = { 2: getcdll('vslinb2d_cu', raise_on_fail=CUDA_RAISE_ON_FAIL), 3: getcdll('vslinb3d_cu', raise_on_fail=CUDA_RAISE_ON_FAIL), } del getcdll @property def _clib_vslinb_c(self): return self.__clib_vslinb_c[self.svr.ndim] @property def _clib_vslinb_cu(self): return self.__clib_vslinb_cu[self.svr.ndim]
class CeseBC(BC): """ Base class for all BC types for CESE method, except periodic BC. @cvar _ghostgeom_: selector for the ghost geometry caculator. @ctype _ghostgeom_: str """ from solvcon.dependency import getcdll __clib_ceseb = { 2: getcdll('ceseb2d', raise_on_fail=False), 3: getcdll('ceseb3d', raise_on_fail=False), } del getcdll @property def _clib_ceseb(self): return self.__clib_ceseb[self.svr.ndim] _ghostgeom_ = None def init(self, **kw): from ctypes import byref, c_int super(CeseBC, self).init(**kw) getattr(self._clib_ceseb, 'ghostgeom_'+self._ghostgeom_)( byref(self.svr.exd), c_int(self.facn.shape[0]), self.facn.ctypes._as_parameter_, ) def soln(self): """ Update ghost cells after marchsol. """ pass def dsoln(self): """ Update ghost cells after marchdsol. """ pass
class CeseSolver(BlockSolver): """ The base solver class for multi-dimensional CESE code. @cvar _gdlen_: length per group data. Must be overridden. @ctype _gdlen_: int @cvar _jacofunc_: ctypes function to Jacobian calculator. Must be overridden. @ctype _jacofunc_: ctypes.FuncPtr @ivar debug: flag for debugging. @itype debug: bool @ivar diffname: name of gradient calculation function; tau is default, omega is selectable. @itype diffname: str @ivar tauname: name of tau function; default linear. @itype tauname: str @ivar omeganame: name of omega function; default scale. @itype omeganame: str @ivar alpha: parameter to the weighting function. @itype alpha: int @ivar taylor: factor for Taylor's expansion; 0 off, 1 on. @itype taylor: float @ivar cnbfac: factor to use BCE centroid, othersize midpoint; 0 off, 1 on. @itype cnbfac: float @ivar sftfac: factor to shift gradient shape; 0 off, 1 on. @itype sftfac: float @ivar taumin: the lower bound of tau. @itype taumin: float @ivar taumax: the upper bound of tau. @itype taumax: float @ivar tauscale: scaling of tau. @itype tauscale: float @ivar omegamin: the lower bound of omega. @itype omegamin: float @ivar omegascale: scaling of omega. @itype omegascale: float @ivar grpda: group data. @ivar cecnd: solution points for CCEs and BCEs. @ivar cevol: CCE and BCE volumes. @ivar solt: temporal diffrentiation of solution. @ivar sol: current solution. @ivar soln: next solution. @ivar dsol: current gradient of solution. @ivar dsoln: next gradient of solution. @ivar cfl: CFL number. @ivar ocfl: original CFL number. @ivar amsca: Parameter scalar array. @ivar amvec: Parameter vector array. """ _exedatatype_ = CeseSolverExedata _interface_init_ = ['cecnd', 'cevol'] _solution_array_ = ['sol', 'soln', 'dsol', 'dsoln'] _gdlen_ = None _jacofunc_ = None def __init__(self, blk, *args, **kw): from numpy import empty self.debug = kw.pop('debug', False) nsca = kw.pop('nsca', 0) nvec = kw.pop('nvec', 0) diffname = kw.pop('diffname', None) self.diffname = diffname if diffname != None else 'tau' tauname = kw.pop('tauname', None) self.tauname = tauname if tauname != None else 'linear' omeganame = kw.pop('omeganame', None) self.omeganame = omeganame if omeganame != None else 'scale' self.alpha = int(kw.pop('alpha', 0)) self.taylor = float(kw.pop('taylor', 1.0)) self.cnbfac = float(kw.pop('cnbfac', 1.0)) self.sftfac = float(kw.pop('sftfac', 1.0)) self.taumin = float(kw.pop('taumin', 0.0)) self.taumax = float(kw.pop('taumax', 1.0)) self.tauscale = float(kw.pop('tauscale', 0.0)) self.omegamin = float(kw.pop('omegamin', 1.1)) self.omegascale = float(kw.pop('omegascale', 0.0)) self.mqmin = float(kw.pop('mqmin', 1.0)) self.mqscale = float(kw.pop('mqscale', 0.0)) super(CeseSolver, self).__init__(blk, *args, **kw) fpdtype = self.fpdtype ndim = self.ndim ncell = self.ncell ngstcell = self.ngstcell neq = self.neq ngroup = self.ngroup # meta array. self.grpda = empty((ngroup, self._gdlen_), dtype=fpdtype) # dual mesh. self.cecnd = empty((ngstcell+ncell, self.CLMFC+1, ndim), dtype=fpdtype) self.cevol = empty((ngstcell+ncell, self.CLMFC+1), dtype=fpdtype) # mesh quality. self.mqlty = empty(ngstcell+ncell, dtype=fpdtype) # solutions. self.solt = empty((ngstcell+ncell, neq), dtype=fpdtype) self.sol = empty((ngstcell+ncell, neq), dtype=fpdtype) self.soln = empty((ngstcell+ncell, neq), dtype=fpdtype) self.dsol = empty((ngstcell+ncell, neq, ndim), dtype=fpdtype) self.dsoln = empty((ngstcell+ncell, neq, ndim), dtype=fpdtype) self.cfl = empty(ncell, dtype=fpdtype) self.ocfl = empty(ncell, dtype=fpdtype) self.amsca = empty((ngstcell+ncell, nsca), dtype=fpdtype) self.amvec = empty((ngstcell+ncell, nvec, ndim), dtype=fpdtype) @property def gdlen(self): """ Length per group data. """ return self._gdlen_ @property def nsca(self): return self.amsca.shape[1] @property def nvec(self): return self.amvec.shape[1] def locate_point(self, *args): from ctypes import byref, c_int, c_void_p from numpy import array crd = array(args, dtype=self.fpdtype) picl = c_int(0) pifl = c_int(0) pjcl = c_int(0) pjfl = c_int(0) self._clib_cese.locate_point( byref(self.exd), crd.ctypes._as_parameter_, byref(picl), byref(pifl), byref(pjcl), byref(pjfl), ) return picl.value, pifl.value, pjcl.value, pjfl.value def init(self, **kw): self._tcall(self._clib_cese.calc_ce, 0, self.ncell) super(CeseSolver, self).init(**kw) def boundcond(self): super(CeseSolver, self).boundcond() self.call_non_interface_bc('soln') self.call_non_interface_bc('dsoln') ################################################## # library. ################################################## from ctypes import c_int from solvcon.dependency import getcdll __clib_cese = { 2: getcdll('cese2d', raise_on_fail=False), 3: getcdll('cese3d', raise_on_fail=False), } del getcdll, c_int @property def _clib_cese(self): return self.__clib_cese[self.ndim] ################################################## # marching algorithm. ################################################## MMNAMES = list() MMNAMES.append('update') def update(self, worker=None): from ctypes import c_void_p if self.debug: self.mesg('update') # exchange solution and gradient. self.sol, self.soln = self.soln, self.sol self.dsol, self.dsoln = self.dsoln, self.dsol # reset pointers in execution data. ngstcell = self.ngstcell self.exd.sol = self.sol[ngstcell:].ctypes._as_parameter_ self.exd.soln = self.soln[ngstcell:].ctypes._as_parameter_ self.exd.dsol = self.dsol[ngstcell:].ctypes._as_parameter_ self.exd.dsoln = self.dsoln[ngstcell:].ctypes._as_parameter_ if self.debug: self.mesg(' done.\n') MMNAMES.append('ibcam') def ibcam(self, worker=None): if self.debug: self.mesg('ibcam') if worker: if self.nsca: self.exchangeibc('amsca', worker=worker) if self.nvec: self.exchangeibc('amvec', worker=worker) if self.debug: self.mesg(' done.\n') MMNAMES.append('calcsolt') def calcsolt(self, worker=None): if self.debug: self.mesg('calcsolt') self._tcall(self._clib_cese.calc_solt, -self.ngstcell, self.ncell, tickerkey='calcsolt') if self.debug: self.mesg(' done.\n') MMNAMES.append('calcsoln') def calcsoln(self, worker=None): if self.debug: self.mesg('calcsoln') func = self._clib_cese.calc_soln self._tcall(func, 0, self.ncell, tickerkey='calcsoln') if self.debug: self.mesg(' done.\n') MMNAMES.append('ibcsoln') def ibcsoln(self, worker=None): if self.debug: self.mesg('ibcsoln') if worker: self.exchangeibc('soln', worker=worker) if self.debug: self.mesg(' done.\n') MMNAMES.append('bcsoln') def bcsoln(self, worker=None): if self.debug: self.mesg('bcsoln') self.call_non_interface_bc('soln') if self.debug: self.mesg(' done.\n') MMNAMES.append('calccfl') def calccfl(self, worker=None): """ @return: mincfl, maxcfl, number of tuned CFL, accumulated number of tuned CFL. @rtype: tuple """ raise NotImplementedError MMNAMES.append('calcdsoln') def calcdsoln(self, worker=None): if self.debug: self.mesg('calcdsoln') func = getattr(self._clib_cese, 'calc_dsoln_'+self.diffname) self._tcall(func, 0, self.ncell, tickerkey='calcdsoln') if self.debug: self.mesg(' done.\n') MMNAMES.append('ibcdsoln') def ibcdsoln(self, worker=None): if self.debug: self.mesg('ibcdsoln') if worker: self.exchangeibc('dsoln', worker=worker) if self.debug: self.mesg(' done.\n') MMNAMES.append('bcdsoln') def bcdsoln(self, worker=None): if self.debug: self.mesg('bcdsoln') self.call_non_interface_bc('dsoln') if self.debug: self.mesg(' done.\n')
class VslinSolver(LincuseSolver): """ Basic elastic solver. @ivar mtrldict: map from names to material objects. @itype mtrldict: dict @ivar mtrllist: list of all material objects. @itype mtrllist: list """ from solvcon.dependency import getcdll __clib_vslin_c = { 2: getcdll('vslin2d_c', raise_on_fail=False), 3: getcdll('vslin3d_c', raise_on_fail=False), } __clib_vslin_cu = { 2: getcdll('vslin2d_cu', raise_on_fail=CUDA_RAISE_ON_FAIL), 3: getcdll('vslin3d_cu', raise_on_fail=CUDA_RAISE_ON_FAIL), } del getcdll @property def _clib_vslin_c(self): return self.__clib_vslin_c[self.ndim] @property def _clib_vslin_cu(self): return self.__clib_vslin_cu[self.ndim] @property def _gdlen_(self): return 9 * 9 * self.ndim def __init__(self, *args, **kw): super(VslinSolver, self).__init__(*args, **kw) self.mtrldict = kw.pop('mtrldict', {}) self.mtrllist = None def make_grpda(self): self.mtrllist = self._build_mtrllist(self.grpnames, self.mtrldict) for igrp in range(len(self.grpnames)): mtrl = self.mtrllist[igrp] jaco = self.grpda[igrp].reshape(self.neq, self.neq, self.ndim) mjacos = mtrl.get_jacos() for idm in range(self.ndim): jaco[:, :, idm] = mjacos[idm, :, :] @staticmethod def _build_mtrllist(grpnames, mtrldict): """ Build the material list out of the mapping dict. @type grpnames: list @param mtrldict: the map from names to material objects. @type mtrldict: dict @return: the list of material object. @rtype: Material """ mtrllist = list() default_mtuple = mtrldict.get(None, None) for grpname in grpnames: try: mtrl = mtrldict.get(grpname, default_mtuple) except KeyError as e: args = e.args[:] args.append('no material named %s in mtrldict' % grpname) e.args = args raise mtrllist.append(mtrl) return mtrllist
class CuseBC(BC): """ Basic BC class for the cuse series solvers. This class support glue BCs. @cvar _ghostgeom_: indicate which ghost geometry processor to use. @ctype _ghostgeom_: str """ _ghostgeom_ = None ########################################################################### # library. ########################################################################### from solvcon.dependency import getcdll __clib_cuseb_c = { 2: getcdll('cuseb2d_c', raise_on_fail=False), 3: getcdll('cuseb3d_c', raise_on_fail=False), } __clib_cuseb_cu = { 2: getcdll('cuseb2d_cu', raise_on_fail=CUDA_RAISE_ON_FAIL), 3: getcdll('cuseb3d_cu', raise_on_fail=CUDA_RAISE_ON_FAIL), } del getcdll @property def _clib_cuseb_c(self): return self.__clib_cuseb_c[self.svr.ndim] @property def _clib_cuseb_cu(self): return self.__clib_cuseb_cu[self.svr.ndim] def bind(self): super(CuseBC, self).bind() if self.svr.scu: for key in ( 'facn', 'value', ): nbytes = getattr(self, key).nbytes setattr(self, 'cu' + key, self.svr.scu.alloc(nbytes)) def unbind(self): if self.svr.scu: for key in ( 'facn', 'value', ): gptr = getattr(self, 'cu' + key, None) if gptr is not None: self.svr.scu.free(getattr(self, 'cu' + key)) def init(self, **kw): from ctypes import byref, c_int super(CuseBC, self).init(**kw) # process ghost geometry. getattr(self._clib_cuseb_c, 'ghostgeom_' + self._ghostgeom_)( byref(self.svr.exd), c_int(self.facn.shape[0]), self.facn.ctypes._as_parameter_) # initialize GPU data. if self.svr.scu: for key in ( 'facn', 'value', ): self.svr.scu.memcpy(getattr(self, 'cu' + key), getattr(self, key)) def soln(self): """ Update ghost cells after self.svr.calcsoln. """ pass def dsoln(self): """ Update ghost cells after self.svr.calcdsoln. """ pass
class CuseSolver(BlockSolver): """ The base solver class for second-order, multi-dimensional CESE code with CUDA enabled. @cvar _gdlen_: length per group data. Must be overridden. @ctype _gdlen_: int @cvar _jacofunc_: ctypes function to Jacobian calculator. Must be overridden. @ctype _jacofunc_: ctypes.FuncPtr @cvar _clib_mcu: ctypes library for physical model on GPU. @ctype _clib_mcu: ctypes.CDLL @ivar debug: flag for debugging. @itype debug: bool @ivar scu: CUDA wrapper. @itype scu: solvcon.scuda.Scuda @ivar ncuth: number of thread per block for CUDA. @itype ncuth: int @ivar alpha: parameter to the weighting function. @itype alpha: int @ivar sigma0: constant parameter for W-3 scheme; should be of order of 1. Default is 3.0. @itype sigma0: float @ivar taylor: factor for Taylor's expansion; 0 off, 1 on. @itype taylor: float @ivar cnbfac: factor to use BCE centroid, othersize midpoint; 0 off, 1 on. @itype cnbfac: float @ivar sftfac: factor to shift gradient shape; 0 off, 1 on. @itype sftfac: float @ivar taumin: the lower bound of tau. @itype taumin: float @ivar tauscale: scaling of tau. @itype tauscale: float @ivar grpda: group data. @ivar cecnd: solution points for CCEs and BCEs. @ivar cevol: CCE and BCE volumes. @ivar sfmrc: sub-face geometry. It is a 5-dimensional array, and the shape is (ncell, CLMFC, FCMND, 2, NDIM). sfmrc[...,0,:] are centers, while sfmrc[...,1,:] are normal vectors. @ivar amsca: Parameter scalar array. @ivar amvec: Parameter vector array. @ivar solt: temporal diffrentiation of solution. @ivar sol: current solution. @ivar soln: next solution. @ivar dsol: current gradient of solution. @ivar dsoln: next gradient of solution. @ivar cfl: CFL number. @ivar ocfl: original CFL number. """ _exedatatype_ = CuseSolverExedata _interface_init_ = ['cecnd', 'cevol'] _solution_array_ = ['sol', 'soln', 'dsol', 'dsoln'] _gdlen_ = None _jacofunc_ = None _clib_mcu = None def __init__(self, blk, *args, **kw): from numpy import empty self.debug = kw.pop('debug', False) # shape parameters. nsca = kw.pop('nsca', 0) nvec = kw.pop('nvec', 0) # CUDA parameters. self.ncuth = kw.pop('ncuth', 0) self.scu = None # scheme parameters. self.alpha = int(kw.pop('alpha', 0)) self.sigma0 = int(kw.pop('sigma0', 3.0)) self.taylor = float(kw.pop('taylor', 1.0)) # dirty hack. self.cnbfac = float(kw.pop('cnbfac', 1.0)) # dirty hack. self.sftfac = float(kw.pop('sftfac', 1.0)) # dirty hack. self.taumin = float(kw.pop('taumin', 0.0)) self.tauscale = float(kw.pop('tauscale', 1.0)) # super call. kw.setdefault('enable_tpool', False) super(CuseSolver, self).__init__(blk, *args, **kw) fpdtype = self.fpdtype ndim = self.ndim ncell = self.ncell ngstcell = self.ngstcell neq = self.neq ngroup = self.ngroup # CUDA manager. self.cumgr = None self.cuarr_map = dict() for key in ('ndcrd', ): self.cuarr_map[key] = self.ngstnode for key in ('fcnds', 'fccls', 'fccnd', 'fcnml', 'fcara'): self.cuarr_map[key] = self.ngstface for key in ('clfcs', 'clcnd', 'cltpn'): self.cuarr_map[key] = self.ngstcell # meta array. self.grpda = empty((ngroup, self._gdlen_), dtype=fpdtype) self.cuarr_map['grpda'] = 0 # dual mesh. self.cecnd = empty((ngstcell + ncell, self.CLMFC + 1, ndim), dtype=fpdtype) self.cevol = empty((ngstcell + ncell, self.CLMFC + 1), dtype=fpdtype) self.cuarr_map['cecnd'] = self.cuarr_map['cevol'] = self.ngstcell self.sfmrc = empty((ncell, self.CLMFC, self.FCMND, 2, ndim), dtype=fpdtype) self.cuarr_map['sfmrc'] = 0 # solutions. self.amsca = empty((ngstcell + ncell, nsca), dtype=fpdtype) self.amvec = empty((ngstcell + ncell, nvec, ndim), dtype=fpdtype) self.solt = empty((ngstcell + ncell, neq), dtype=fpdtype) self.sol = empty((ngstcell + ncell, neq), dtype=fpdtype) self.soln = empty((ngstcell + ncell, neq), dtype=fpdtype) self.dsol = empty((ngstcell + ncell, neq, ndim), dtype=fpdtype) self.dsoln = empty((ngstcell + ncell, neq, ndim), dtype=fpdtype) self.stm = empty((ngstcell + ncell, neq), dtype=fpdtype) self.cfl = empty(ngstcell + ncell, dtype=fpdtype) self.ocfl = empty(ngstcell + ncell, dtype=fpdtype) for key in ('amsca', 'amvec', 'solt', 'sol', 'soln', 'dsol', 'dsoln', 'stm', 'cfl', 'ocfl'): self.cuarr_map[key] = self.ngstcell @property def gdlen(self): """ Length per group data. """ return self._gdlen_ @property def nsca(self): return self.amsca.shape[1] @property def nvec(self): return self.amvec.shape[1] def bind(self): from solvcon.conf import env self.scu = env.scu if self.ncuth else None if self.scu: self.cumgr = CudaDataManager(svr=self) super(CuseSolver, self).bind() def unbind(self): if self.scu and self.cumgr is not None: self.cumgr.free_all() self.cumgr = None super(CuseSolver, self).unbind() def init(self, **kw): from ctypes import byref self._clib_cuse_c.prepare_ce(byref(self.exd)) super(CuseSolver, self).init(**kw) self._clib_cuse_c.prepare_sf(byref(self.exd)) if self.scu: self.cumgr.arr_to_gpu() self.mesg('cuda is %s\n' % ('on' if self.scu else 'off')) def boundcond(self): if self.scu: self.cumgr.update_exd() self.cumgr.arr_to_gpu('sol', 'soln', 'dsol', 'dsoln') if self.nsca: self.cumgr.arr_to_gpu('amsca') if self.nvec: self.cumgr.arr_to_gpu('amvec') super(CuseSolver, self).boundcond() self.call_non_interface_bc('soln') if self.scu: self.cumgr.arr_from_gpu('sol', 'soln') self.call_non_interface_bc('dsoln') if self.scu: self.cumgr.arr_from_gpu('dsol', 'dsoln') ########################################################################### # parallelization. ########################################################################### def pushibc(self, arrname, bc, recvn, worker=None): """ Push data toward selected interface which connect to blocks with larger serial number than myself. If CUDA is present, data are first uploaded to and then downloaded from GPU. @param arrname: name of the array in the object to exchange. @type arrname: str @param bc: the interface BC to push. @type bc: solvcon.boundcond.interface @param recvn: serial number of the peer to exchange data with. @type recvn: int @keyword worker: the wrapping worker object for parallel processing. @type worker: solvcon.rpc.Worker """ from numpy import empty conn = worker.pconns[bc.rblkn] ngstcell = self.ngstcell arr = getattr(self, arrname) shape = list(arr.shape) shape[0] = bc.rclp.shape[0] # for CUDA up/download. if self.scu: stride = arr.itemsize for size in arr.shape[1:]: stride *= size # ask the receiver for data. rarr = empty(shape, dtype=arr.dtype) conn.recvarr(rarr) # comm. # set array and upload to GPU. slct = bc.rclp[:, 0] + ngstcell if self.scu: gslct = self.scu.alloc(slct.nbytes) self.scu.memcpy(gslct, slct) gbrr = self.scu.alloc(rarr.nbytes) self.scu.memcpy(gbrr, rarr) garr = self.cumgr[arrname] self._clib_cuse_cu.slct_io(self.ncuth, 0, len(slct), stride, gslct.gptr, garr.gptr, gbrr.gptr) else: arr[slct] = rarr[:] # download from GPU and get array. slct = bc.rclp[:, 2] + ngstcell if self.scu: self.scu.memcpy(gslct, slct) self._clib_cuse_cu.slct_io(self.ncuth, 1, len(slct), stride, gslct.gptr, garr.gptr, gbrr.gptr) self.scu.memcpy(rarr, gbrr) self.scu.free(gbrr) self.scu.free(gslct) else: rarr[:] = arr[slct] # provide the receiver with data. conn.sendarr(rarr) # comm. def pullibc(self, arrname, bc, sendn, worker=None): """ Pull data from the interface determined by the serial of peer. If CUDA is present, data are first downloaded from GPU and then uploaded to GPU. @param arrname: name of the array in the object to exchange. @type arrname: str @param bc: the interface BC to pull. @type bc: solvcon.boundcond.interface @param sendn: serial number of the peer to exchange data with. @type sendn: int @keyword worker: the wrapping worker object for parallel processing. @type worker: solvcon.rpc.Worker """ from numpy import empty conn = worker.pconns[bc.rblkn] ngstcell = self.ngstcell arr = getattr(self, arrname) shape = list(arr.shape) shape[0] = bc.rclp.shape[0] # for CUDA up/download. if self.scu: stride = arr.itemsize for size in arr.shape[1:]: stride *= size # download from GPU and get array. slct = bc.rclp[:, 2] + ngstcell rarr = empty(shape, dtype=arr.dtype) if self.scu: gslct = self.scu.alloc(slct.nbytes) self.scu.memcpy(gslct, slct) gbrr = self.scu.alloc(rarr.nbytes) garr = self.cumgr[arrname] self._clib_cuse_cu.slct_io(self.ncuth, 1, len(slct), stride, gslct.gptr, garr.gptr, gbrr.gptr) self.scu.memcpy(rarr, gbrr) else: rarr[:] = arr[slct] # provide sender the data. conn.sendarr(rarr) # comm. # ask data from sender. conn.recvarr(rarr) # comm. # set array and upload to GPU. slct = bc.rclp[:, 0] + ngstcell if self.scu: self.scu.memcpy(gslct, slct) self.scu.memcpy(gbrr, rarr) self._clib_cuse_cu.slct_io(self.ncuth, 0, len(slct), stride, gslct.gptr, garr.gptr, gbrr.gptr) self.scu.free(gbrr) self.scu.free(gslct) else: arr[slct] = rarr[:] ########################################################################### # utility. ########################################################################### def locate_point(self, *args): """ Locate the cell index where the input coordinate is. """ from ctypes import byref, c_int from numpy import array crd = array(args, dtype='float64') picl = c_int(0) pifl = c_int(0) pjcl = c_int(0) pjfl = c_int(0) self._clib_cuse_c.locate_point(byref(self.exd), crd.ctypes._as_parameter_, byref(picl), byref(pifl), byref(pjcl), byref(pjfl)) return picl.value, pifl.value, pjcl.value, pjfl.value ########################################################################### # library. ########################################################################### from solvcon.dependency import getcdll __clib_cuse_c = { 2: getcdll('cuse2d_c', raise_on_fail=False), 3: getcdll('cuse3d_c', raise_on_fail=False), } __clib_cuse_cu = { 2: getcdll('cuse2d_cu', raise_on_fail=CUDA_RAISE_ON_FAIL), 3: getcdll('cuse3d_cu', raise_on_fail=CUDA_RAISE_ON_FAIL), } del getcdll @property def _clib_cuse_c(self): return self.__clib_cuse_c[self.ndim] @property def _clib_cuse_cu(self): return self.__clib_cuse_cu[self.ndim] ########################################################################### # marching algorithm. ########################################################################### MMNAMES = list() MMNAMES.append('update') def update(self, worker=None): if self.debug: self.mesg('update') # exchange solution and gradient. self.sol, self.soln = self.soln, self.sol self.dsol, self.dsoln = self.dsoln, self.dsol # exchange pointers in execution data. exd = self.exd exd.sol, exd.soln = exd.soln, exd.sol exd.dsol, exd.dsoln = exd.dsoln, exd.dsol # exchange items in GPU execution data. if self.scu: cumgr = self.cumgr cumgr.sol, cumgr.soln = cumgr.soln, cumgr.sol cumgr.dsol, cumgr.dsoln = cumgr.dsoln, cumgr.dsol cumgr.update_exd() if self.debug: self.mesg(' done.\n') MMNAMES.append('ibcam') def ibcam(self, worker=None): if self.debug: self.mesg('ibcam') if worker: if self.nsca: self.exchangeibc('amsca', worker=worker) if self.nvec: self.exchangeibc('amvec', worker=worker) if self.debug: self.mesg(' done.\n') MMNAMES.append('calcsolt') def calcsolt(self, worker=None): from ctypes import byref if self.debug: self.mesg('calcsolt') if self.scu: self._clib_mcu.calc_solt(self.ncuth, byref(self.cumgr.exd), self.cumgr.gexd.gptr) else: self._clib_cuse_c.calc_solt(byref(self.exd), -self.ngstcell, self.ncell) if self.debug: self.mesg(' done.\n') MMNAMES.append('calcsoln') def calcsoln(self, worker=None): from ctypes import byref if self.debug: self.mesg('calcsoln') if self.scu: self._clib_mcu.calc_soln(self.ncuth, byref(self.cumgr.exd), self.cumgr.gexd.gptr) else: self._clib_cuse_c.calc_soln(byref(self.exd)) if self.debug: self.mesg(' done.\n') MMNAMES.append('ibcsoln') def ibcsoln(self, worker=None): if self.debug: self.mesg('ibcsoln') if worker: self.exchangeibc('soln', worker=worker) if self.debug: self.mesg(' done.\n') MMNAMES.append('bcsoln') def bcsoln(self, worker=None): if self.debug: self.mesg('bcsoln') self.call_non_interface_bc('soln') if self.debug: self.mesg(' done.\n') MMNAMES.append('calccfl') def calccfl(self, worker=None): raise NotImplementedError MMNAMES.append('calcdsoln') def calcdsoln(self, worker=None): from ctypes import byref if self.debug: self.mesg('calcdsoln') if self.scu: self._clib_mcu.calc_dsoln_w3(self.ncuth, byref(self.cumgr.exd), self.cumgr.gexd.gptr) else: self._clib_cuse_c.calc_dsoln_w3(byref(self.exd)) if self.debug: self.mesg(' done.\n') MMNAMES.append('ibcdsoln') def ibcdsoln(self, worker=None): if self.debug: self.mesg('ibcdsoln') if worker: self.exchangeibc('dsoln', worker=worker) if self.debug: self.mesg(' done.\n') MMNAMES.append('bcdsoln') def bcdsoln(self, worker=None): if self.debug: self.mesg('bcdsoln') self.call_non_interface_bc('dsoln') if self.debug: self.mesg(' done.\n')