def _solve_varproblem(*args, **kwargs): "Solve variational problem a == L or F == 0" # Extract arguments eq, u, bcs, J, Jp, M, form_compiler_parameters, solver_parameters, nullspace \ = _extract_args(*args, **kwargs) # Solve linear variational problem if isinstance(eq.lhs, ufl.Form) and isinstance(eq.rhs, ufl.Form): # Create problem problem = vs.LinearVariationalProblem(eq.lhs, eq.rhs, u, bcs, Jp, form_compiler_parameters=form_compiler_parameters) # Create solver and call solve solver = vs.LinearVariationalSolver(problem, solver_parameters=solver_parameters, nullspace=nullspace) with progress(INFO, 'Solving linear variational problem'): solver.solve() # Solve nonlinear variational problem else: # Create problem problem = vs.NonlinearVariationalProblem(eq.lhs, u, bcs, J, Jp, form_compiler_parameters=form_compiler_parameters) # Create solver and call solve solver = vs.NonlinearVariationalSolver(problem, solver_parameters=solver_parameters, nullspace=nullspace) with progress(INFO, 'Solving nonlinear variational problem'): solver.solve() # destroy snes part of solver so everything can be gc'd solver.destroy()
def _solve_varproblem(*args, **kwargs): "Solve variational problem a == L or F == 0" # Extract arguments eq, u, bcs, J, Jp, M, form_compiler_parameters, \ solver_parameters, nullspace, nullspace_T, options_prefix, \ nest = _extract_args(*args, **kwargs) # Solve linear variational problem if isinstance(eq.lhs, ufl.Form) and isinstance(eq.rhs, ufl.Form): # Create problem problem = vs.LinearVariationalProblem( eq.lhs, eq.rhs, u, bcs, Jp, form_compiler_parameters=form_compiler_parameters, nest=nest) # Create solver and call solve solver = vs.LinearVariationalSolver( problem, solver_parameters=solver_parameters, nullspace=nullspace, transpose_nullspace=nullspace_T, options_prefix=options_prefix) with progress(INFO, 'Solving linear variational problem'): solver.solve() # Solve nonlinear variational problem else: if eq.rhs != 0: raise TypeError( "Only '0' support on RHS of nonlinear Equation, not %r" % eq.rhs) # Create problem problem = vs.NonlinearVariationalProblem( eq.lhs, u, bcs, J, Jp, form_compiler_parameters=form_compiler_parameters, nest=nest) # Create solver and call solve solver = vs.NonlinearVariationalSolver( problem, solver_parameters=solver_parameters, nullspace=nullspace, transpose_nullspace=nullspace_T, options_prefix=options_prefix) with progress(INFO, 'Solving nonlinear variational problem'): solver.solve()
def _solve_varproblem(*args, **kwargs): "Solve variational problem a == L or F == 0" # Extract arguments eq, u, bcs, J, Jp, M, form_compiler_parameters, \ solver_parameters, nullspace, nullspace_T, options_prefix, \ nest = _extract_args(*args, **kwargs) # Solve linear variational problem if isinstance(eq.lhs, ufl.Form) and isinstance(eq.rhs, ufl.Form): # Create problem problem = vs.LinearVariationalProblem(eq.lhs, eq.rhs, u, bcs, Jp, form_compiler_parameters=form_compiler_parameters, nest=nest) # Create solver and call solve solver = vs.LinearVariationalSolver(problem, solver_parameters=solver_parameters, nullspace=nullspace, transpose_nullspace=nullspace_T, options_prefix=options_prefix) with progress(INFO, 'Solving linear variational problem'): solver.solve() # Solve nonlinear variational problem else: if eq.rhs != 0: raise TypeError("Only '0' support on RHS of nonlinear Equation, not %r" % eq.rhs) # Create problem problem = vs.NonlinearVariationalProblem(eq.lhs, u, bcs, J, Jp, form_compiler_parameters=form_compiler_parameters, nest=nest) # Create solver and call solve solver = vs.NonlinearVariationalSolver(problem, solver_parameters=solver_parameters, nullspace=nullspace, transpose_nullspace=nullspace_T, options_prefix=options_prefix) with progress(INFO, 'Solving nonlinear variational problem'): solver.solve()
def get_so(self, src, extension): """Build a shared library and load it :arg src: The source string to compile. :arg extension: extension of the source file (c, cpp). Returns a :class:`ctypes.CDLL` object of the resulting shared library.""" # Determine cache key hsh = md5(src.encode()) hsh.update(self._cc.encode()) if self._ld: hsh.update(self._ld.encode()) hsh.update("".join(self._cppargs).encode()) hsh.update("".join(self._ldargs).encode()) basename = hsh.hexdigest() cachedir = configuration['cache_dir'] pid = os.getpid() cname = os.path.join(cachedir, "%s_p%d.%s" % (basename, pid, extension)) oname = os.path.join(cachedir, "%s_p%d.o" % (basename, pid)) soname = os.path.join(cachedir, "%s.so" % basename) # Link into temporary file, then rename to shared library # atomically (avoiding races). tmpname = os.path.join(cachedir, "%s_p%d.so.tmp" % (basename, pid)) if configuration['check_src_hashes'] or configuration['debug']: matching = self.comm.allreduce(basename, op=_check_op) if matching != basename: # Dump all src code to disk for debugging output = os.path.join(cachedir, "mismatching-kernels") srcfile = os.path.join(output, "src-rank%d.c" % self.comm.rank) if self.comm.rank == 0: if not os.path.exists(output): os.makedirs(output, exist_ok=True) self.comm.barrier() with open(srcfile, "w") as f: f.write(src) self.comm.barrier() raise CompilationError("Generated code differs across ranks (see output in %s)" % output) try: # Are we in the cache? return ctypes.CDLL(soname) except OSError: # No, let's go ahead and build if self.comm.rank == 0: # No need to do this on all ranks if not os.path.exists(cachedir): os.makedirs(cachedir, exist_ok=True) logfile = os.path.join(cachedir, "%s_p%d.log" % (basename, pid)) errfile = os.path.join(cachedir, "%s_p%d.err" % (basename, pid)) with progress(INFO, 'Compiling wrapper'): with open(cname, "w") as f: f.write(src) # Compiler also links if self._ld is None: cc = [self._cc] + self._cppargs + \ ['-o', tmpname, cname] + self._ldargs debug('Compilation command: %s', ' '.join(cc)) with open(logfile, "w") as log: with open(errfile, "w") as err: log.write("Compilation command:\n") log.write(" ".join(cc)) log.write("\n\n") try: if configuration['no_fork_available']: cc += ["2>", errfile, ">", logfile] cmd = " ".join(cc) status = os.system(cmd) if status != 0: raise subprocess.CalledProcessError(status, cmd) else: subprocess.check_call(cc, stderr=err, stdout=log) except subprocess.CalledProcessError as e: raise CompilationError( """Command "%s" return error status %d. Unable to compile code Compile log in %s Compile errors in %s""" % (e.cmd, e.returncode, logfile, errfile)) else: cc = [self._cc] + self._cppargs + \ ['-c', '-o', oname, cname] ld = self._ld.split() + ['-o', tmpname, oname] + self._ldargs debug('Compilation command: %s', ' '.join(cc)) debug('Link command: %s', ' '.join(ld)) with open(logfile, "w") as log: with open(errfile, "w") as err: log.write("Compilation command:\n") log.write(" ".join(cc)) log.write("\n\n") log.write("Link command:\n") log.write(" ".join(ld)) log.write("\n\n") try: if configuration['no_fork_available']: cc += ["2>", errfile, ">", logfile] ld += ["2>", errfile, ">", logfile] cccmd = " ".join(cc) ldcmd = " ".join(ld) status = os.system(cccmd) if status != 0: raise subprocess.CalledProcessError(status, cccmd) status = os.system(ldcmd) if status != 0: raise subprocess.CalledProcessError(status, ldcmd) else: subprocess.check_call(cc, stderr=err, stdout=log) subprocess.check_call(ld, stderr=err, stdout=log) except subprocess.CalledProcessError as e: raise CompilationError( """Command "%s" return error status %d. Unable to compile code Compile log in %s Compile errors in %s""" % (e.cmd, e.returncode, logfile, errfile)) # Atomically ensure soname exists os.rename(tmpname, soname) # Wait for compilation to complete self.comm.barrier() # Load resulting library return ctypes.CDLL(soname)
def get_so(self, jitmodule, extension): """Build a shared library and load it :arg jitmodule: The JIT Module which can generate the code to compile. :arg extension: extension of the source file (c, cpp). Returns a :class:`ctypes.CDLL` object of the resulting shared library.""" # Determine cache key hsh = md5(str(jitmodule.cache_key).encode()) hsh.update(self._cc.encode()) if self._ld: hsh.update(self._ld.encode()) hsh.update("".join(self._cppargs).encode()) hsh.update("".join(self._ldargs).encode()) basename = hsh.hexdigest() cachedir = configuration['cache_dir'] dirpart, basename = basename[:2], basename[2:] cachedir = os.path.join(cachedir, dirpart) pid = os.getpid() cname = os.path.join(cachedir, "%s_p%d.%s" % (basename, pid, extension)) oname = os.path.join(cachedir, "%s_p%d.o" % (basename, pid)) soname = os.path.join(cachedir, "%s.so" % basename) # Link into temporary file, then rename to shared library # atomically (avoiding races). tmpname = os.path.join(cachedir, "%s_p%d.so.tmp" % (basename, pid)) if configuration['check_src_hashes'] or configuration['debug']: matching = self.comm.allreduce(basename, op=_check_op) if matching != basename: # Dump all src code to disk for debugging output = os.path.join(cachedir, "mismatching-kernels") srcfile = os.path.join(output, "src-rank%d.c" % self.comm.rank) if self.comm.rank == 0: os.makedirs(output, exist_ok=True) self.comm.barrier() with open(srcfile, "w") as f: f.write(jitmodule.code_to_compile) self.comm.barrier() raise CompilationError("Generated code differs across ranks (see output in %s)" % output) try: # Are we in the cache? return ctypes.CDLL(soname) except OSError: # No, let's go ahead and build if self.comm.rank == 0: # No need to do this on all ranks os.makedirs(cachedir, exist_ok=True) logfile = os.path.join(cachedir, "%s_p%d.log" % (basename, pid)) errfile = os.path.join(cachedir, "%s_p%d.err" % (basename, pid)) with progress(INFO, 'Compiling wrapper'): with open(cname, "w") as f: f.write(jitmodule.code_to_compile) # Compiler also links if self._ld is None: cc = [self._cc] + self._cppargs + \ ['-o', tmpname, cname] + self._ldargs debug('Compilation command: %s', ' '.join(cc)) with open(logfile, "w") as log: with open(errfile, "w") as err: log.write("Compilation command:\n") log.write(" ".join(cc)) log.write("\n\n") try: if configuration['no_fork_available']: cc += ["2>", errfile, ">", logfile] cmd = " ".join(cc) status = os.system(cmd) if status != 0: raise subprocess.CalledProcessError(status, cmd) else: subprocess.check_call(cc, stderr=err, stdout=log) except subprocess.CalledProcessError as e: raise CompilationError( """Command "%s" return error status %d. Unable to compile code Compile log in %s Compile errors in %s""" % (e.cmd, e.returncode, logfile, errfile)) else: cc = [self._cc] + self._cppargs + \ ['-c', '-o', oname, cname] ld = self._ld.split() + ['-o', tmpname, oname] + self._ldargs debug('Compilation command: %s', ' '.join(cc)) debug('Link command: %s', ' '.join(ld)) with open(logfile, "w") as log: with open(errfile, "w") as err: log.write("Compilation command:\n") log.write(" ".join(cc)) log.write("\n\n") log.write("Link command:\n") log.write(" ".join(ld)) log.write("\n\n") try: if configuration['no_fork_available']: cc += ["2>", errfile, ">", logfile] ld += ["2>", errfile, ">", logfile] cccmd = " ".join(cc) ldcmd = " ".join(ld) status = os.system(cccmd) if status != 0: raise subprocess.CalledProcessError(status, cccmd) status = os.system(ldcmd) if status != 0: raise subprocess.CalledProcessError(status, ldcmd) else: subprocess.check_call(cc, stderr=err, stdout=log) subprocess.check_call(ld, stderr=err, stdout=log) except subprocess.CalledProcessError as e: raise CompilationError( """Command "%s" return error status %d. Unable to compile code Compile log in %s Compile errors in %s""" % (e.cmd, e.returncode, logfile, errfile)) # Atomically ensure soname exists os.rename(tmpname, soname) # Wait for compilation to complete self.comm.barrier() # Load resulting library return ctypes.CDLL(soname)
def _la_solve(A, x, b, bcs=None, parameters=None, nullspace=None): """Solves a linear algebra problem. :arg A: the assembled bilinear form, a :class:`.Matrix`. :arg x: the :class:`.Function` to write the solution into. :arg b: the :class:`.Function` defining the right hand side values. :arg bcs: an optional list of :class:`.DirichletBC`\s to apply. :arg parameters: optional solver parameters. :arg nullspace: an optional :class:`.VectorSpaceBasis` (or :class:`.MixedVectorSpaceBasis`) spanning the null space of the operator. .. note:: Any boundary conditions passed in as an argument here override the boundary conditions set when the bilinear form was assembled. That is, in the following example: .. code-block:: python A = assemble(a, bcs=[bc1]) solve(A, x, b, bcs=[bc2]) the boundary conditions in `bc2` will be applied to the problem while `bc1` will be ignored. Example usage: .. code-block:: python _la_solve(A, x, b, parameters=parameters_dict) The linear solver and preconditioner are selected by looking at the parameters dict, if it is empty, the defaults are taken from PyOP2 (see :var:`pyop2.DEFAULT_SOLVER_PARAMETERS`).""" # Make sure we don't stomp on a dict the user has passed in. parameters = copy(parameters) if parameters is not None else {} parameters.setdefault('ksp_type', 'gmres') parameters.setdefault('pc_type', 'ilu') if A._M.sparsity.shape != (1, 1): parameters.setdefault('pc_type', 'jacobi') solver = op2.Solver(parameters=parameters) if A.has_bcs and bcs is None: # Pick up any BCs on the linear operator bcs = A.bcs elif bcs is not None: # Override using bcs from solve call A.bcs = _extract_bcs(bcs) if bcs is not None: # Solving A x = b - action(a, u_bc) u_bc = function.Function(b.function_space()) for bc in bcs: bc.apply(u_bc) # rhs = b - action(A, u_bc) u_bc.assign(b - A._form_action(u_bc)) # Now we need to apply the boundary conditions to the "RHS" for bc in bcs: bc.apply(u_bc) # don't want to write into b itself, because that would confuse user b = u_bc if nullspace is not None: nullspace._apply(A._M) with progress(INFO, 'Solving linear system'): solver.solve(A.M, x.dat, b.dat) x.dat.halo_exchange_begin() x.dat.halo_exchange_end()