def dx(self, x, id, baseid=None): # NOTE: pu functions are evaluated in physical coordinates, basis functions in reference coordinates node = self._pu._tree[id] vfdx = np.zeros(node.dim) if node.bbox.is_inside(x, scaling=self._pu._scaling): if baseid is None: # evaluate all base functions at once tx = AffineMap.eval_inverse_map(node.bbox, x, scaling=self._pu._scaling) vfdx = [f.dx(tx) for f in self._basisset[id]] vfdx *= 1 / (self._pu.scaling * self._pu._tree[id].size) # scale basis gradients if self._with_pu: vf = [f(tx) for f in self._basisset[id]] vpu = self._pu(x, id) vpudx = self._pu.dx(x, id) # pu gradients are already scaled vfdx = [fdx * vpu + f * vpudx for f, fdx in zip(vf, vfdx)] else: # evaluate single basis vfdx = np.zeros(node.dim) tx = AffineMap.eval_inverse_map(node.bbox, x, scaling=self._pu._scaling) vfdx = self._basisset[id][baseid](tx) vfdx *= 1 / (self._pu.scaling * self._pu._tree[id].size) # scale basis gradients if self._with_pu: vf = self._basisset[id][baseid](tx) vpu = self._pu(x, id) vpudx = self._pu.dx(x, id) # pu gradients are already scaled vfdx = vfdx * vpu + vf * vpudx return vfdx
def __call__(self, x, id, baseid=None): # NOTE: pu functions are evaluated in physical coordinates, basis functions in reference coordinates vf = 0.0 node = self._pu._tree[id] if node.bbox.is_inside(x, scaling=self._pu._scaling): if baseid is None: # evaluate all base functions at once tx = AffineMap.eval_inverse_map(node.bbox, x, scaling=self._pu._scaling) vf = [f(tx) for f in self._basisset[id]] if self._with_pu: vpu = self._pu(x, id) vf = [vpu * v for v in vf] else: # evaluate single basis tx = AffineMap.eval_inverse_map(node.bbox, x, scaling=self._pu._scaling) vf = self._basisset[id][baseid](tx) if self._with_pu: vpu = self._pu(x, id) vf = vpu * vf return vf