def concatenateRow(*args): """ """ if len(args) == 1: return args[0] if len(args) > 2: return concatenateRow(args[0], concatenateRow(*args[1:])) lshape = util.getShape(args[0]) rshape = util.getShape(args[1]) if len(lshape) == 0: if len(rshape) == 0: shape = (2, ) res = numpy.zeros(shape, dtype=object) res[0] = args[0] res[1] = args[1] elif len(rshape) == 1: shape = (rshape[0] + 1, ) res = numpy.zeros(shape, dtype=object) res[0] = args[0] res[1:] = args[1] elif len(lshape) == 1: if len(rshape) == 1: shape = (2, ) + lshape res = numpy.zeros(shape, dtype=object) res[0] = args[0] res[1] = args[1] else: shape = (rshape[0] + 1, ) + lshape res = numpy.zeros(shape, dtype=object) res[0] = args[0] res[1:] = args[1] else: if len(rshape) == 1: shape = (lshape[0] + 1, ) + lshape[1:] res = numpy.zeros(shape, dtype=object) res[:lshape[0]] = args[0] res[lshape[0]] = args[1] else: shape = (lshape[0] + rshape[0], ) + lshape[1:] res = numpy.zeros(shape, dtype=object) res[:lshape[0]] = args[0] res[lshape[0]:] = args[1] subs = args[0].getDataSubstitutions().copy() subs.update(args[1].getDataSubstitutions()) dim = args[1].getDim() if args[0].getDim() < 0 else args[0].getDim() return symb.Symbol(res, dim=dim, subs=subs)
def createCoefficient(self, name): """ Creates a new coefficient ``name`` as Symbol :param name: name of the coefficient requested :type name: ``string`` :return: the value of the coefficient :rtype: `Symbol` or `Data` (for name = "q") :raise IllegalCoefficient: if ``name`` is not a coefficient of the PDE """ if name == "q": return self._lpde.createCoefficient("q") else: s = self.getShapeOfCoefficient(name) return symb.Symbol(name, s, dim=self.dim)
def getSolution(self, **subs): """ Returns the solution of the PDE. :param subs: Substitutions for all symbols used in the coefficients including the initial value for the unknown *u*. :return: the solution :rtype: `Data` """ # get the initial value for the iteration process # collect components of unknown in u_syms u_syms = [] simple_u = False for i in numpy.ndindex(self._unknown.getShape()): u_syms.append( symb.Symbol(self._unknown[i]).atoms(sympy.Symbol).pop().name) if len(set(u_syms)) == 1: simple_u = True e = symb.Evaluator(self._unknown) for sym in u_syms: if not sym in subs: raise KeyError("Initial value for '%s' missing." % sym) if not isinstance(subs[sym], Data): subs[sym] = Data(subs[sym], self._lpde.getFunctionSpaceForSolution()) e.subs(**{sym: subs[sym]}) ui = e.evaluate() # modify ui so it meets the constraints: q = self._lpde.getCoefficient("q") if not q.isEmpty(): if hasattr(self, "_r"): r = self._r if symb.isSymbol(r): r = symb.Evaluator(r).evaluate(**subs) elif not isinstance(r, Data): r = Data(r, self._lpde.getFunctionSpaceForSolution()) elif r.isEmpty(): r = 0 else: r = 0 ui = q * r + (1 - q) * ui # separate symbolic expressions from other coefficients constants = {} expressions = {} for n, e in sorted(self._set_coeffs.items(), key=lambda x: x[0]): if symb.isSymbol(e): expressions[n] = e else: constants[n] = e # set constant PDE values now self._lpde.setValue(**constants) self._lpde.getSolverOptions().setAbsoluteTolerance(0.) self._lpde.getSolverOptions().setVerbosity(self._debug > self.DEBUG1) #===================================================================== # perform Newton iterations until error is small enough or # maximum number of iterations reached n = 0 omega = 1. # relaxation factor use_simplified_Newton = False defect_norm = None delta_norm = None converged = False #subs[u_sym]=ui if simple_u: subs[u_syms[0]] = ui else: for i in range(len(u_syms)): subs[u_syms[i]] = ui[i] while not converged: if n > self._iteration_steps_max: raise iteration_steps_maxReached( "maximum number of iteration steps reached, giving up.") self.trace1(5 * "=" + " iteration step %d " % n + 5 * "=") # calculate the correction delta_u if n == 0: self._updateLinearPDE(expressions, subs, **constants) defect_norm = self._getDefectNorm( self._lpde.getRightHandSide()) LINTOL = 0.1 else: if not use_simplified_Newton: self._updateMatrix(expressions, subs) if q_u is None: LINTOL = 0.1 * min(qtol / defect_norm) else: LINTOL = 0.1 * max(q_u**2, min(qtol / defect_norm)) LINTOL = max(1e-4, min(LINTOL, 0.1)) #LINTOL=1.e-5 self._lpde.getSolverOptions().setTolerance(LINTOL) self.trace1("PDE is solved with rel. tolerance = %e" % LINTOL) delta_u = self._lpde.getSolution() #check for reduced defect: omega = min(2 * omega, 1.) # raise omega defect_reduced = False ui_old = ui while not defect_reduced: ui = ui_old - delta_u * omega if simple_u: subs[u_syms[0]] = ui else: for i in range(len(u_syms)): subs[u_syms[i]] = ui[i] self._updateRHS(expressions, subs, **constants) new_defect_norm = self._getDefectNorm( self._lpde.getRightHandSide()) defect_reduced = False for i in range(len(new_defect_norm)): if new_defect_norm[i] < defect_norm[i]: defect_reduced = True #print new_defect_norm #q_defect=max(self._getSafeRatio(new_defect_norm, defect_norm)) # if defect_norm==0 and new_defect_norm!=0 # this will be util.DBLE_MAX #self.trace1("Defect reduction = %e with relaxation factor %e."%(q_defect, omega)) if not defect_reduced: omega *= 0.5 if omega < self._omega_min: raise DivergenceDetected( "Underrelaxtion failed to reduce defect, giving up." ) self.trace1("Defect reduction with relaxation factor %e." % (omega, )) delta_norm, delta_norm_old = self._getSolutionNorm( delta_u) * omega, delta_norm defect_norm, defect_norm_old = new_defect_norm, defect_norm u_norm = self._getSolutionNorm(ui, atol=self._atol) # set the tolerance on equation level: qtol = self._getSafeRatio(defect_norm_old * u_norm * self._rtol, delta_norm) # if defect_norm_old==0 and defect_norm_old!=0 this will be util.DBLE_MAX # -> the ordering of the equations is not appropriate. # if defect_norm_old==0 and defect_norm_old==0 this is zero so # convergence can happen for defect_norm==0 only. if not max(qtol) < util.DBLE_MAX: raise InadmissiblePDEOrdering( "Review ordering of PDE equations.") # check stopping criteria if not delta_norm_old is None: q_u = max(self._getSafeRatio(delta_norm, delta_norm_old)) # if delta_norm_old==0 and delta_norm!=0 # this will be util.DBLE_MAX if q_u <= self._quadratic_convergence_limit and not omega < 1.: quadratic_convergence = True self.trace1( "Quadratic convergence detected (rate %e <= %e)" % (q_u, self._quadratic_convergence_limit)) converged = all( [defect_norm[i] <= qtol[i] for i in range(len(qtol))]) else: self.trace1( "No quadratic convergence detected (rate %e > %e, omega=%e)" % (q_u, self._quadratic_convergence_limit, omega)) quadratic_convergence = False converged = False else: q_u = None converged = False quadratic_convergence = False if self._debug > self.DEBUG0: for i in range(len(u_norm)): self.trace1( "Component %s: u: %e, du: %e, defect: %e, qtol: %e" % (i, u_norm[i], delta_norm[i], defect_norm[i], qtol[i])) if converged: self.trace1("Iteration has converged.") # Can we switch to simplified Newton? if quadratic_convergence: q_defect = max(self._getSafeRatio(defect_norm, defect_norm_old)) if q_defect < self._simplified_newton_limit: use_simplified_Newton = True self.trace1( "Simplified Newton-Raphson is applied (rate %e < %e)." % (q_defect, self._simplified_newton_limit)) n += 1 self.trace1(5 * "=" + " Newton-Raphson iteration completed after %d steps " % n + 5 * "=") return ui