def getSensitivity(self, f, g=None, **subs): """ Calculates the sensitivity of the solution of an input factor ``f`` in direction ``g``. :param f: the input factor to be investigated. ``f`` may be of rank 0 or 1. :type f: `Symbol` :param g: the direction(s) of change. If not present, it is *g=eye(n)* where ``n`` is the number of components of ``f``. :type g: ``list`` or single of ``float``, ``numpy.array`` or `Data`. :param subs: Substitutions for all symbols used in the coefficients including unknown *u* and the input factor ``f`` to be investigated :return: the sensitivity :rtype: `Data` with shape *u.getShape()+(len(g),)* if *len(g)>1* or *u.getShape()* if *len(g)==1* """ s_f = f.getShape() if len(s_f) == 0: len_f = 1 elif len(s_f) == 1: len_f = s_f[0] else: raise ValueError("rank of input factor must be zero or one.") if not g is None: if len(s_f) == 0: if not isinstance(g, list): g = [g] else: if isinstance(g, list): if len(g) == 0: raise ValueError("no direction given.") if len(getShape(g[0])) == 0: g = [ g ] # if g[0] is a scalar we assume that the list g is to be interprested a data object else: g = [g] # at this point g is a list of directions: len_g = len(g) for g_i in g: if not getShape(g_i) == s_f: raise ValueError( "shape of direction (=%s) must match rank of input factor (=%s)" % (getShape(g_i), s_f)) else: len_g = len_f #*** at this point g is a list of direction or None and len_g is the # number of directions to be investigated. # now we make sure that the operator in the lpde is set (it is the same # as for the Newton-Raphson scheme) # if the solution etc are cached this could be omitted: constants = {} expressions = {} for n, e in sorted(self._set_coeffs.items(), key=lambda x: x[0]): if n not in self.__COEFFICIENTS: if symb.isSymbol(e): expressions[n] = e else: constants[n] = e self._lpde.setValue(**constants) self._updateMatrix(self, expressions, subs) #===================================================================== self._lpde.getSolverOptions().setAbsoluteTolerance(0.) self._lpde.getSolverOptions().setTolerance(self._rtol) self._lpde.getSolverOptions().setVerbosity(self._debug > self.DEBUG1) #===================================================================== # # evaluate the derivatives of X, etc with respect to f: # ev = symb.Evaluator() names = [] if hasattr(self, "_r"): if symb.isSymbol(self._r): names.append('r') ev.addExpression(self._r.diff(f)) for n in sorted(self._set_coeffs.keys()): if n in self.__COEFFICIENTS and symb.isSymbol(self._set_coeffs[n]): if n == "X" or n == "X_reduced": T0 = time() B, A = symb.getTotalDifferential(self._set_coeffs[n], f, 1) if n == 'X_reduced': self.trace3( "Computing A_reduced, B_reduced took %f seconds." % (time() - T0)) names.append('A_reduced') ev.addExpression(A) names.append('B_reduced') ev.addExpression(B) else: self.trace3("Computing A, B took %f seconds." % (time() - T0)) names.append('A') ev.addExpression(A) names.append('B') ev.addExpression(B) elif n == "Y" or n == "Y_reduced": T0 = time() D, C = symb.getTotalDifferential(self._set_coeffs[n], f, 1) if n == 'Y_reduced': self.trace3( "Computing C_reduced, D_reduced took %f seconds." % (time() - T0)) names.append('C_reduced') ev.addExpression(C) names.append('D_reduced') ev.addExpression(D) else: self.trace3("Computing C, D took %f seconds." % (time() - T0)) names.append('C') ev.addExpression(C) names.append('D') ev.addExpression(D) elif n in ("y", "y_reduced", "y_contact", "y_contact_reduced", "y_dirac"): names.append('d' + name[1:]) ev.addExpression(self._set_coeffs[name].diff(f)) relevant_symbols['d' + name[1:]] = self._set_coeffs[name].diff(f) res = ev.evaluate() if len(names) == 1: res = [res] self.trace3("RHS expressions evaluated in %f seconds." % (time() - T0)) if self._debug > self.DEBUG2: for i in range(len(names)): self.trace3("util.Lsup(%s)=%s" % (names[i], util.Lsup(res[i]))) coeffs_f = dict(zip(names, res)) # # now we are ready to calculate the right hand side coefficients into # args by multiplication with g and grad(g). if len_g > 1: if self.getNumSolutions() == 1: u_g = Data(0., (len_g, ), self._lpde.getFunctionSpaceForSolution()) else: u_g = Data(0., (self.getNumSolutions(), len_g), self._lpde.getFunctionSpaceForSolution()) for i in range(len_g): # reset coefficients may be set at previous calls: args = {} for n in self.__COEFFICIENTS: args[n] = Data() args['r'] = Data() if g is None: # g_l=delta_{il} and len_f=len_g for n, v in coeffs_f: name = None if len_f > 1: val = v[:, i] else: val = v if n.startswith("d"): name = 'y' + n[1:] elif n.startswith("D"): name = 'Y' + n[1:] elif n.startswith("r"): name = 'r' + n[1:] if name: args[name] = val else: g_i = g[i] for n, v in coeffs_f: name = None if n.startswith("d"): name = 'y' + n[1:] val = self.__mm(v, g_i) elif n.startswith("r"): name = 'r' val = self.__mm(v, g_i) elif n.startswith("D"): name = 'Y' + n[1:] val = self.__mm(v, g_i) elif n.startswith("B") and isinstance(g_i, Data): name = 'Y' + n[1:] val = self.__mm(v, grad(g_i)) elif n.startswith("C"): name = 'X' + n[1:] val = matrix_multiply(v, g_i) elif n.startswith("A") and isinstance(g_i, Data): name = 'X' + n[1:] val = self.__mm(v, grad(g_i)) if name: if name in args: args[name] += val else: args[name] = val self._lpde.setValue(**args) u_g_i = self._lpde.getSolution() if len_g > 1: if self.getNumSolutions() == 1: u_g[i] = -u_g_i else: u_g[:, i] = -u_g_i else: u_g = -u_g_i return u_g
def getSensitivity(self, f, g=None, **subs): """ Calculates the sensitivity of the solution of an input factor ``f`` in direction ``g``. :param f: the input factor to be investigated. ``f`` may be of rank 0 or 1. :type f: `Symbol` :param g: the direction(s) of change. If not present, it is *g=eye(n)* where ``n`` is the number of components of ``f``. :type g: ``list`` or single of ``float``, ``numpy.array`` or `Data`. :param subs: Substitutions for all symbols used in the coefficients including unknown *u* and the input factor ``f`` to be investigated :return: the sensitivity :rtype: `Data` with shape *u.getShape()+(len(g),)* if *len(g)>1* or *u.getShape()* if *len(g)==1* """ s_f=f.getShape() if len(s_f) == 0: len_f=1 elif len(s_f) == 1: len_f=s_f[0] else: raise ValueError("rank of input factor must be zero or one.") if not g is None: if len(s_f) == 0: if not isinstance(g, list): g=[g] else: if isinstance(g, list): if len(g) == 0: raise ValueError("no direction given.") if len(getShape(g[0])) == 0: g=[g] # if g[0] is a scalar we assume that the list g is to be interprested a data object else: g=[g] # at this point g is a list of directions: len_g=len(g) for g_i in g: if not getShape(g_i) == s_f: raise ValueError("shape of direction (=%s) must match rank of input factor (=%s)"%(getShape(g_i) , s_f) ) else: len_g=len_f #*** at this point g is a list of direction or None and len_g is the # number of directions to be investigated. # now we make sure that the operator in the lpde is set (it is the same # as for the Newton-Raphson scheme) # if the solution etc are cached this could be omitted: constants={} expressions={} for n, e in sorted(self._set_coeffs.items(), key=lambda x: x[0]): if n not in self.__COEFFICIENTS: if symb.isSymbol(e): expressions[n]=e else: constants[n]=e self._lpde.setValue(**constants) self._updateMatrix(self, expressions, subs) #===================================================================== self._lpde.getSolverOptions().setAbsoluteTolerance(0.) self._lpde.getSolverOptions().setTolerance(self._rtol) self._lpde.getSolverOptions().setVerbosity(self._debug > self.DEBUG1) #===================================================================== # # evaluate the derivatives of X, etc with respect to f: # ev=symb.Evaluator() names=[] if hasattr(self, "_r"): if symb.isSymbol(self._r): names.append('r') ev.addExpression(self._r.diff(f)) for n in sorted(self._set_coeffs.keys()): if n in self.__COEFFICIENTS and symb.isSymbol(self._set_coeffs[n]): if n=="X" or n=="X_reduced": T0=time() B,A=symb.getTotalDifferential(self._set_coeffs[n], f, 1) if n=='X_reduced': self.trace3("Computing A_reduced, B_reduced took %f seconds."%(time()-T0)) names.append('A_reduced'); ev.addExpression(A) names.append('B_reduced'); ev.addExpression(B) else: self.trace3("Computing A, B took %f seconds."%(time()-T0)) names.append('A'); ev.addExpression(A) names.append('B'); ev.addExpression(B) elif n=="Y" or n=="Y_reduced": T0=time() D,C=symb.getTotalDifferential(self._set_coeffs[n], f, 1) if n=='Y_reduced': self.trace3("Computing C_reduced, D_reduced took %f seconds."%(time()-T0)) names.append('C_reduced'); ev.addExpression(C) names.append('D_reduced'); ev.addExpression(D) else: self.trace3("Computing C, D took %f seconds."%(time()-T0)) names.append('C'); ev.addExpression(C) names.append('D'); ev.addExpression(D) elif n in ("y", "y_reduced", "y_contact", "y_contact_reduced", "y_dirac"): names.append('d'+name[1:]); ev.addExpression(self._set_coeffs[name].diff(f)) relevant_symbols['d'+name[1:]]=self._set_coeffs[name].diff(f) res=ev.evaluate() if len(names)==1: res=[res] self.trace3("RHS expressions evaluated in %f seconds."%(time()-T0)) if self._debug > self.DEBUG2: for i in range(len(names)): self.trace3("util.Lsup(%s)=%s"%(names[i],util.Lsup(res[i]))) coeffs_f=dict(zip(names,res)) # # now we are ready to calculate the right hand side coefficients into # args by multiplication with g and grad(g). if len_g >1: if self.getNumSolutions() == 1: u_g=Data(0., (len_g,), self._lpde.getFunctionSpaceForSolution()) else: u_g=Data(0., (self.getNumSolutions(), len_g), self._lpde.getFunctionSpaceForSolution()) for i in range(len_g): # reset coefficients may be set at previous calls: args={} for n in self.__COEFFICIENTS: args[n]=Data() args['r']=Data() if g is None: # g_l=delta_{il} and len_f=len_g for n,v in coeffs_f: name=None if len_f > 1: val=v[:,i] else: val=v if n.startswith("d"): name='y'+n[1:] elif n.startswith("D"): name='Y'+n[1:] elif n.startswith("r"): name='r'+n[1:] if name: args[name]=val else: g_i=g[i] for n,v in coeffs_f: name=None if n.startswith("d"): name = 'y'+n[1:] val = self.__mm(v, g_i) elif n.startswith("r"): name= 'r' val = self.__mm(v, g_i) elif n.startswith("D"): name = 'Y'+n[1:] val = self.__mm(v, g_i) elif n.startswith("B") and isinstance(g_i, Data): name = 'Y'+n[1:] val = self.__mm(v, grad(g_i)) elif n.startswith("C"): name = 'X'+n[1:] val = matrix_multiply(v, g_i) elif n.startswith("A") and isinstance(g_i, Data): name = 'X'+n[1:] val = self.__mm(v, grad(g_i)) if name: if name in args: args[name]+=val else: args[name]=val self._lpde.setValue(**args) u_g_i=self._lpde.getSolution() if len_g >1: if self.getNumSolutions() == 1: u_g[i]=-u_g_i else: u_g[:,i]=-u_g_i else: u_g=-u_g_i return u_g
def setValue(self, **coefficients): """ Sets new values to one or more coefficients. :param coefficients: new values assigned to coefficients :param coefficients: new values assigned to coefficients :keyword X: value for coefficient ``X`` :type X: `Symbol` or any type that can be cast to a `Data` object :keyword Y: value for coefficient ``Y`` :type Y: `Symbol` or any type that can be cast to a `Data` object :keyword y: value for coefficient ``y`` :type y: `Symbol` or any type that can be cast to a `Data` object :keyword y_contact: value for coefficient ``y_contact`` :type y_contact: `Symbol` or any type that can be cast to a `Data` object :keyword y_dirac: value for coefficient ``y_dirac`` :type y_dirac: `Symbol` or any type that can be cast to a `Data` object :keyword q: mask for location of constraint :type q: any type that can be cast to a `Data` object :keyword r: value of solution prescribed by constraint :type r: `Symbol` or any type that can be cast to a `Data` object :raise IllegalCoefficient: if an unknown coefficient keyword is used :raise IllegalCoefficientValue: if a supplied coefficient value has an invalid shape """ u = self._unknown for name, val in sorted(coefficients.items(), key=lambda x: x[0]): shape = util.getShape(val) if not shape == self.getShapeOfCoefficient(name): raise lpe.IllegalCoefficientValue( "%s has shape %s but must have shape %s" % (name, shape, self.getShapeOfCoefficient(name))) rank = len(shape) if name == "q": self._lpde.setValue(q=val) elif name == "r": self._r = val elif name == "X" or name == "X_reduced": if rank != u.getRank() + 1: raise lpe.IllegalCoefficientValue("%s must have rank %d" % (name, u.getRank() + 1)) T0 = time() B, A = symb.getTotalDifferential(val, u, 1) if name == 'X_reduced': self.trace3( "Computing A_reduced, B_reduced took %f seconds." % (time() - T0)) self._set_coeffs['A_reduced'] = A self._set_coeffs['B_reduced'] = B self._set_coeffs['X_reduced'] = val else: self.trace3("Computing A, B took %f seconds." % (time() - T0)) self._set_coeffs['A'] = A self._set_coeffs['B'] = B self._set_coeffs['X'] = val elif name == "Y" or name == "Y_reduced": if rank != u.getRank(): raise lpe.IllegalCoefficientValue("%s must have rank %d" % (name, u.getRank())) T0 = time() D, C = symb.getTotalDifferential(val, u, 1) if name == 'Y_reduced': self.trace3( "Computing C_reduced, D_reduced took %f seconds." % (time() - T0)) self._set_coeffs['C_reduced'] = C self._set_coeffs['D_reduced'] = D self._set_coeffs['Y_reduced'] = val else: self.trace3("Computing C, D took %f seconds." % (time() - T0)) self._set_coeffs['C'] = C self._set_coeffs['D'] = D self._set_coeffs['Y'] = val elif name in ("y", "y_reduced", "y_contact", "y_contact_reduced", \ "y_dirac"): y = val if rank != u.getRank(): raise lpe.IllegalCoefficientValue("%s must have rank %d" % (name, u.getRank())) if not hasattr(y, 'diff'): d = numpy.zeros(u.getShape() + u.getShape()) else: d = y.diff(u) self._set_coeffs[name] = y self._set_coeffs['d' + name[1:]] = d else: raise lpe.IllegalCoefficient( "Attempt to set unknown coefficient %s" % name)
def setValue(self,**coefficients): """ Sets new values to one or more coefficients. :param coefficients: new values assigned to coefficients :param coefficients: new values assigned to coefficients :keyword X: value for coefficient ``X`` :type X: `Symbol` or any type that can be cast to a `Data` object :keyword Y: value for coefficient ``Y`` :type Y: `Symbol` or any type that can be cast to a `Data` object :keyword y: value for coefficient ``y`` :type y: `Symbol` or any type that can be cast to a `Data` object :keyword y_contact: value for coefficient ``y_contact`` :type y_contact: `Symbol` or any type that can be cast to a `Data` object :keyword y_dirac: value for coefficient ``y_dirac`` :type y_dirac: `Symbol` or any type that can be cast to a `Data` object :keyword q: mask for location of constraint :type q: any type that can be cast to a `Data` object :keyword r: value of solution prescribed by constraint :type r: `Symbol` or any type that can be cast to a `Data` object :raise IllegalCoefficient: if an unknown coefficient keyword is used :raise IllegalCoefficientValue: if a supplied coefficient value has an invalid shape """ u=self._unknown for name,val in sorted(coefficients.items(), key=lambda x: x[0]): shape=util.getShape(val) if not shape == self.getShapeOfCoefficient(name): raise lpe.IllegalCoefficientValue("%s has shape %s but must have shape %s"%(name, shape, self.getShapeOfCoefficient(name))) rank=len(shape) if name == "q": self._lpde.setValue(q=val) elif name == "r": self._r=val elif name=="X" or name=="X_reduced": if rank != u.getRank()+1: raise lpe.IllegalCoefficientValue("%s must have rank %d"%(name,u.getRank()+1)) T0=time() B,A=symb.getTotalDifferential(val, u, 1) if name=='X_reduced': self.trace3("Computing A_reduced, B_reduced took %f seconds."%(time()-T0)) self._set_coeffs['A_reduced']=A self._set_coeffs['B_reduced']=B self._set_coeffs['X_reduced']=val else: self.trace3("Computing A, B took %f seconds."%(time()-T0)) self._set_coeffs['A']=A self._set_coeffs['B']=B self._set_coeffs['X']=val elif name=="Y" or name=="Y_reduced": if rank != u.getRank(): raise lpe.IllegalCoefficientValue("%s must have rank %d"%(name,u.getRank())) T0=time() D,C=symb.getTotalDifferential(val, u, 1) if name=='Y_reduced': self.trace3("Computing C_reduced, D_reduced took %f seconds."%(time()-T0)) self._set_coeffs['C_reduced']=C self._set_coeffs['D_reduced']=D self._set_coeffs['Y_reduced']=val else: self.trace3("Computing C, D took %f seconds."%(time()-T0)) self._set_coeffs['C']=C self._set_coeffs['D']=D self._set_coeffs['Y']=val elif name in ("y", "y_reduced", "y_contact", "y_contact_reduced", \ "y_dirac"): y=val if rank != u.getRank(): raise lpe.IllegalCoefficientValue("%s must have rank %d"%(name,u.getRank())) if not hasattr(y, 'diff'): d=numpy.zeros(u.getShape()+u.getShape()) else: d=y.diff(u) self._set_coeffs[name]=y self._set_coeffs['d'+name[1:]]=d else: raise lpe.IllegalCoefficient("Attempt to set unknown coefficient %s"%name)