Source code for cil.optimisation.operators.SymmetrisedGradientOperator
# Copyright 2019 United Kingdom Research and Innovation# Copyright 2019 The University of Manchester## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.## Authors:# CIL Developers, listed at: https://github.com/TomographicImaging/CIL/blob/master/NOTICE.txtfromcil.optimisation.operatorsimportLinearOperatorfromcil.frameworkimportBlockGeometry,BlockDataContainerfromcil.optimisation.operatorsimportFiniteDifferenceOperator
[docs]classSymmetrisedGradientOperator(LinearOperator):r''' The symmetrised gradient is the operator, :math:`E`, defined by :math:`E: V \rightarrow W` where `V` is `BlockGeometry` and `W` is the range of the Symmetrised Gradient and .. math:: E(v) = 0.5 ( \nabla v + (\nabla v)^{T} ) \\ In 2 dimensions, let :math:`v(x,y)=(v_1(x,y),v_2(x,y))` which gives .. math:: \nabla v =\left( \begin{matrix} \partial_{x} v_1 & \partial_x v_2\\ \partial_{y}v_1 & \partial_y v_2 \end{matrix}\right) and thus .. math:: E(v) = 0.5 ( \nabla v + (\nabla v)^{T} ) =\left( \begin{matrix} \partial_{x} v_1 & 0.5 (\partial_{y} v_1 + \partial_{x} v_2) \\ 0.5 (\partial_{x} v_1 + \partial_{y} v_2) & \partial_{y} v_2 \end{matrix}\right) Parameters ---------- domain_geometry: `BlockGeometry` with shape (2,1) or (3,1) Set up the domain of the function. bnd_cond: str, optional, default :code:`Neumann` Boundary condition either :code:`Neumann` or :code:`Periodic` correlation: str, optional, default :code:`Channel` Correlation either :code:`SpaceChannel` or :code:`Channel` '''CORRELATION_SPACE="Space"CORRELATION_SPACECHANNEL="SpaceChannels"def__init__(self,domain_geometry,bnd_cond='Neumann',**kwargs):self.bnd_cond=bnd_condself.correlation=kwargs.get('correlation',SymmetrisedGradientOperator.CORRELATION_SPACE)tmp_gm=len(domain_geometry.geometries)*domain_geometry.geometries# Define FD operator. We need one geometry from the BlockGeometry of the domainself.FD=FiniteDifferenceOperator(domain_geometry.get_item(0),direction=0,bnd_cond=self.bnd_cond)ifdomain_geometry.shape[0]==2:self.order_ind=[0,2,1,3]else:self.order_ind=[0,3,6,1,4,7,2,5,8]super(SymmetrisedGradientOperator,self).__init__(domain_geometry=domain_geometry,range_geometry=BlockGeometry(*tmp_gm))
[docs]defdirect(self,x,out=None):r'''Returns :math:`E(v) = 0.5 * ( \nabla v + (\nabla v)^{T} )` Parameters: ------------- x: BlockDataContainer out: BlockDataContainer, default None If out is not None the output of direct will be filled in out, otherwise a new object is instantiated and returned. '''ifoutisNone:tmp=[]foriinrange(self.domain_geometry().shape[0]):forjinrange(x.shape[0]):self.FD.direction=itmp.append(self.FD.adjoint(x.get_item(j)))tmp1=[tmp[i]foriinself.order_ind]res=[0.5*sum(x)forxinzip(tmp,tmp1)]returnBlockDataContainer(*res)else:ind=0foriinrange(self.domain_geometry().shape[0]):forjinrange(x.shape[0]):self.FD.direction=iself.FD.adjoint(x.get_item(j),out=out[ind])ind+=1out1=BlockDataContainer(*[out[i]foriinself.order_ind])out.fill(0.5*(out+out1))returnout
[docs]defadjoint(self,x,out=None):r'''Returns the adjoint of the symmetrised gradient operator Parameters: ------------- x: BlockDataContainer out: BlockDataContainer, default None If out is not None the output of adjoint will be filled in out, otherwise a new object is instantiated and returned. '''ifoutisNone:tmp=[None]*self.domain_geometry().shape[0]i=0forkinrange(self.domain_geometry().shape[0]):tmp1=0forjinrange(self.domain_geometry().shape[0]):self.FD.direction=jtmp1+=self.FD.direct(x[i])i+=1tmp[k]=tmp1returnBlockDataContainer(*tmp)else:tmp=self.domain_geometry().allocate()i=0forkinrange(self.domain_geometry().shape[0]):tmp1=0forjinrange(self.domain_geometry().shape[0]):self.FD.direction=jself.FD.direct(x[i],out=tmp[j])i+=1tmp1+=tmp[j]out[k].fill(tmp1)returnout