Beispiel #1
0
    def test_CartesianTransformation3D(self):
      
         dom=Brick(NE,NE,NE, l0=10, l1=10, l2=10)
         
         cs=CartesianReferenceSystem()
         tf=cs.createTransformation(dom)
         
         self.assertEqual(tf.getReferenceSystem(),cs , "wrong reference")
         self.assertEqual(tf.getDomain(),dom , "wrong reference")
         self.assertTrue(tf.isCartesian(), "wrong isCartesian check")
         
         
         v=tf.getVolumeFactor()
         self.assertTrue(isinstance(v, esys.escript.Data), "wrong volume factor type")
         self.assertEqual(v.getFunctionSpace(), esys.escript.Function(dom), "wrong volume factor type")
         error=Lsup(v-1.)
         self.assertTrue(error<=RTOL, "volume factor")
         
         s=tf.getScalingFactors()
         self.assertTrue(isinstance(s, esys.escript.Data), "scaling factor type")
         self.assertEqual(s.getShape(), (dom.getDim(),), "scaling factor length")
         self.assertEqual(s.getFunctionSpace(), esys.escript.Function(dom), "wrong 0-th scaling factor type")

         error=Lsup(s[0]-1.)
         self.assertTrue(error<=RTOL, "0-th scaling factor")         
         error=Lsup(s[1]-1.)
         self.assertTrue(error<=RTOL, "1-th scaling factor")  
         error=Lsup(s[2]-1.)
         self.assertTrue(error<=RTOL, "2-th scaling factor")   
 def setUp(self):
     self.domain = Brick(n0=NE0 * NXb - 1,
                         n1=NE1 * NYb - 1,
                         n2=NE2 * NZb - 1,
                         d0=NXb,
                         d1=NYb,
                         d2=NZb)
     self.package = SolverOptions.MKL
     self.method = SolverOptions.DIRECT
Beispiel #3
0
    def __createDomain(self):
        """
        Creates and returns an escript domain that spans the entire area of
        available data plus a padding zone. This method is called only once
        the first time `getDomain()` is invoked.

        :return: The escript domain
        :rtype: `esys.escript.Domain`
        """
        X0, NX, DX = self.__getTotalExtentsWithPadding()

        # number of domain elements
        NE = NX + [self._v_num_cells]

        # origin of domain
        origin = X0 + [-self._v_depth*self.__v_scale]

        if self.getReferenceSystem().isCartesian():
            # rounding will give us about meter-accuracy with UTM coordinates
            self._dom_origin = [np.floor(oi) for oi in origin]
        else:
            # this should give us about meter-accuracy with lat/lon coords
            self._dom_origin = [1e-5*np.floor(oi*1e5) for oi in origin]

        # cell size / point spacing
        spacing = DX + [self.__v_scale*np.floor((self._v_depth+self._v_air_layer)/self._v_num_cells)]
        #self._spacing = [float(np.floor(si)) for si in spacing]
        self._spacing = spacing

        lo=[(self._dom_origin[i], self._dom_origin[i]+NE[i]*self._spacing[i]) for i in range(self.__dim)]

        if self.__dim==3:
            dom=Brick(*NE, l0=lo[0], l1=lo[1], l2=lo[2])
        else:
            dom=Rectangle(*NE, l0=lo[0], l1=lo[1])

        # ripley may internally adjust NE and length, so recompute
        self._dom_len=[sup(dom.getX()[i])-inf(dom.getX()[i]) for i in range(self.__dim)]
        self._dom_NE=[int(self._dom_len[i]/self._spacing[i]) for i in range(self.__dim)]

        self.logger.debug("Domain size: "+str(self._dom_NE))
        self.logger.debug("     length: "+str(self._dom_len))
        self.logger.debug("     origin: "+str(self._dom_origin))
        return dom
Beispiel #4
0
 def setUp(self):
     self.domain = Brick(10,
                         10,
                         10,
                         l0=100.,
                         l1=100.,
                         l2=100.,
                         diracTags=["source"],
                         diracPoints=[(0, 0, 0)])
     self.wavelet = Ricker(100.)
Beispiel #5
0
 def setUp(self):
     self.domain = Brick(n0=NE0 * NXb - 1,
                         n1=NE1 * NYb - 1,
                         n2=NE2 * NZb - 1,
                         d0=NXb,
                         d1=NYb,
                         d2=NZb)
     self.package = SolverOptions.TRILINOS
     self.method = SolverOptions.PCG
     self.preconditioner = SolverOptions.ILUT
Beispiel #6
0
 def setUp(self):
     self.order = 1
     self.domain = Brick(n0=NE * NXb - 1,
                         n1=NE * NYb - 1,
                         n2=NE * NZb - 1,
                         l0=1.,
                         l1=1.,
                         l2=1.,
                         d0=NXb,
                         d1=NYb,
                         d2=NZb)
Beispiel #7
0
 def test_FillBrick(self):
     # If we are going to do really big tests of this, the size of this brick will need to be reduced
     fs = ContinuousFunction(Brick(10 * mpiSize, 10 * mpiSize,
                                   10 * mpiSize))
     RandomData((), fs, 2, ("gaussian", 1, 0.5))
     RandomData((), fs, 0, ("gaussian", 2, 0.76))
     self.assertRaises(NotImplementedError, RandomData, (2, 2), fs, 0,
                       ("gaussian", 2, 0.76))  #data not scalar
     self.assertRaises(ValueError, RandomData, (), fs, 0,
                       ("gaussian", 20, 0.1))  #radius too large
     RandomData((2, 3), fs)
Beispiel #8
0
    def test_Creation(self):
        r = self.numRanks
        el = self.numRanks * 3 - 1

        #test bad types
        with self.assertRaises(TypeError):
            Rectangle(5, el, d1=r, diracPoints=(.0, 0.), diracTags=["test"])
        with self.assertRaises(TypeError):
            Rectangle(5, el, d1=r, diracPoints=[(.0, 0.)], diracTags=("test"))
        with self.assertRaises(TypeError):
            Rectangle(5, el, d1=r, diracPoints=[.0], diracTags=["test"])
        with self.assertRaises(TypeError):
            Rectangle(5, el, d1=r, diracPoints=[.0, .0], diracTags=["test"])

        with self.assertRaises(TypeError):
            Brick(5, el, 5, d1=r, diracPoints=(.0, 0., 0.), diracTags=["test"])
        with self.assertRaises(TypeError):
            Brick(5,
                  el,
                  5,
                  d1=r,
                  diracPoints=[(.0, 0., 0.)],
                  diracTags=("test"))
        with self.assertRaises(TypeError):
            Brick(5, el, 5, d1=r, diracPoints=[.0, 0.], diracTags=["test"])

        #test bad arg lengths
        with self.assertRaises(RuntimeError):
            Rectangle(5, el, d1=r, diracPoints=[(.0, )], diracTags=["test"])
        with self.assertRaises(RuntimeError):
            Rectangle(5, el, d1=r, diracPoints=[(.0, 1.)], diracTags=[])
        with self.assertRaises(RuntimeError):
            Rectangle(5,
                      el,
                      d1=r,
                      diracPoints=[(.0, 0.)],
                      diracTags=["test", "break"])
        with self.assertRaises(RuntimeError):
            Rectangle(5,
                      el,
                      d1=r,
                      diracPoints=[(.0, 0., 0.)],
                      diracTags=["test"])

        with self.assertRaises(RuntimeError):
            Brick(5,
                  el,
                  5,
                  d1=r,
                  diracPoints=[(.0, 0., 0., 0.)],
                  diracTags=["test"])
        with self.assertRaises(RuntimeError):
            Brick(5, el, 5, d1=r, diracPoints=[(
                .0,
                0.,
            )], diracTags=["test"])
        with self.assertRaises(RuntimeError):
            Brick(5, el, 5, d1=r, diracPoints=[(.0, )], diracTags=["test"])
 def test_SphericalTransformation3D(self):
   
      dom=Brick(NE,NE,NE, l0=90, l1=45, l2=10.)
      
      cs=SphericalReferenceSystem()
      tf=cs.createTransformation(dom)
      
      self.assertEqual(tf.getReferenceSystem(),cs , "wrong reference")
      self.assertEqual(tf.getDomain(),dom , "wrong reference")
      self.assertFalse(tf.isCartesian(), "wrong isCartesian check")
      
      R=6378137.0
      x=esys.escript.Function(dom).getX()
      phi=(90.-x[1])/180.*pi
      lam=x[0]/180.*pi
      h=x[2]*1000.
      r=h+R
      
      v=tf.getVolumeFactor()
      self.assertTrue(isinstance(v, esys.escript.Data), "wrong volume factor type")
      self.assertEqual(v.getFunctionSpace(), esys.escript.Function(dom), "wrong volume factor type")
      error=Lsup(v- r**2*sin(phi)*(pi/180.)**2*1000. )
      self.assertTrue(error<=RTOL * R*R*(pi/180.)**2*1000., "volume factor")
      
      s=tf.getScalingFactors()
      self.assertTrue(isinstance(s, esys.escript.Data), "scaling factor type")
      self.assertEqual(s.getShape(), (dom.getDim(),), "scaling factor length")
      self.assertEqual(s.getFunctionSpace(), esys.escript.Function(dom), "wrong 0-th scaling factor type")
      
      error=Lsup(s[1]-1/r/pi*180.)
      self.assertTrue(error<=RTOL/R/pi*180., "0-th scaling factor")         
      
      error=Lsup(s[0]-1/(r*sin(phi))/pi*180.)
      self.assertTrue(error<=RTOL/R/pi*180., "1-th scaling factor")  
      
      error=Lsup(s[2]-1./1000.)
      self.assertTrue(error<=RTOL/1000., "2-th scaling factor")   
Beispiel #10
0
 def test_SphericalTransformation3D(self):
   
      dom=Brick(NE,NE,NE, l0=90, l1=45, l2=10.)
      
      cs=SphericalReferenceSystem()
      tf=cs.createTransformation(dom)
      
      self.assertEqual(tf.getReferenceSystem(),cs , "wrong reference")
      self.assertEqual(tf.getDomain(),dom , "wrong reference")
      self.assertFalse(tf.isCartesian(), "wrong isCartesian check")
      
      R=6378137.0
      x=esys.escript.Function(dom).getX()
      phi=(90.-x[1])/180.*pi
      lam=x[0]/180.*pi
      h=x[2]*1000.
      r=h+R
      
      v=tf.getVolumeFactor()
      self.assertTrue(isinstance(v, esys.escript.Data), "wrong volume factor type")
      self.assertEqual(v.getFunctionSpace(), esys.escript.Function(dom), "wrong volume factor type")
      error=Lsup(v- r**2*sin(phi)*(pi/180.)**2*1000. )
      self.assertTrue(error<=RTOL * R*R*(pi/180.)**2*1000., "volume factor")
      
      s=tf.getScalingFactors()
      self.assertTrue(isinstance(s, esys.escript.Data), "scaling factor type")
      self.assertEqual(s.getShape(), (dom.getDim(),), "scaling factor length")
      self.assertEqual(s.getFunctionSpace(), esys.escript.Function(dom), "wrong 0-th scaling factor type")
      
      error=Lsup(s[1]-1/r/pi*180.)
      self.assertTrue(error<=RTOL/R/pi*180., "0-th scaling factor")         
      
      error=Lsup(s[0]-1/(r*sin(phi))/pi*180.)
      self.assertTrue(error<=RTOL/R/pi*180., "1-th scaling factor")  
      
      error=Lsup(s[2]-1./1000.)
      self.assertTrue(error<=RTOL/1000., "2-th scaling factor")   
Beispiel #11
0
class TestGravityApp(unittest.TestCase):

    xdim = 1000.
    ydim = 1000.
    zdim = 1000.
    NEX = 100
    NEZ = 100
    TESTTOL = 1e-3

    def setUp(self):
        self.domain = Brick(self.NEX,
                            self.NEX,
                            self.NEZ,
                            l0=self.xdim,
                            l1=self.ydim,
                            l2=self.zdim)

    def tearDown(self):
        del self.domain

    def test_pde_answer(self):
        model = GravityModel(self.domain, fixBase=True)
        x = self.domain.getX()
        xmin = inf(x[0])
        xmax = sup(x[0])
        ymin = inf(x[1])
        ymax = sup(x[1])
        zmin = inf(x[2])
        zmax = sup(x[2])
        xp = 2. * np.pi / (xmax - xmin)
        yp = 2. * np.pi / (ymax - ymin)
        zp = 2. * np.pi / (zmax - zmin)
        Dens = (xp**2 + yp**2 + zp**2) * cos(xp * x[0]) * cos(yp * x[1]) * sin(
            zp * x[2]) / (4.0 * np.pi * U.Gravitational_Constant)
        model.setDensity(Dens)
        outdens = model.getDensity()
        densdiff = abs(Dens - outdens)
        self.assertLessEqual(sup(densdiff), self.TESTTOL)
        actualanswer = -cos(xp * x[0]) * cos(yp * x[1]) * sin(zp * x[2])
        abserror = abs(actualanswer - model.getGravityPotential())
        biggesterror = sup(abserror)
        self.assertLessEqual(biggesterror, self.TESTTOL)
        gz = model.getzGravity()
        actualgz = -zp * cos(xp * x[0]) * cos(yp * x[1]) * cos(zp * x[2])
        errorgz = abs(gz - actualgz)
        self.assertLessEqual(sup(errorgz), self.TESTTOL * 100.)
Beispiel #12
0
 def setUp(self):
     self.domain = Brick(n0=NE * NXb - 1,
                         n1=NE * NYb - 1,
                         n2=NE * NZb - 1,
                         l0=1.,
                         l1=1.,
                         l2=1.,
                         d0=NXb,
                         d1=NYb,
                         d2=NZb)
     self.functionspaces = [
         ContinuousFunction(self.domain),
         Function(self.domain),
         ReducedFunction(self.domain),
         FunctionOnBoundary(self.domain),
         ReducedFunctionOnBoundary(self.domain)
     ]
Beispiel #13
0
class TestMagneticApp3D(unittest.TestCase):

    xdim = 1000.
    ydim = 1000.
    zdim = 1000.
    NEX = 100
    NEZ = 100
    TESTTOL = 1e-3

    def setUp(self):
        self.domain = Brick(self.NEX,
                            self.NEX,
                            self.NEZ,
                            l0=self.xdim,
                            l1=self.ydim,
                            l2=self.zdim)

    def tearDown(self):
        del self.domain

    def test_pde_answer(self):
        model = MagneticModel3D(self.domain, fixVert=True)
        x = self.domain.getX()
        xmin = inf(x[0])
        xmax = sup(x[0])
        ymin = inf(x[1])
        ymax = sup(x[1])
        zmin = inf(x[2])
        zmax = sup(x[2])
        xp = 2. * np.pi / (xmax - xmin)
        yp = 2. * np.pi / (ymax - ymin)
        zp = 2. * np.pi / (zmax - zmin)
        Bh = [1., 0., 0.]
        k = ((xp**2 + yp**2 + zp**2) / xp) * cos(xp * x[0]) * sin(
            yp * x[1]) * cos(zp * x[2])
        model.setSusceptibility(k)
        outk = model.getSusceptibility()
        kdiff = abs(k - outk)
        self.assertLessEqual(sup(kdiff), self.TESTTOL)
        model.setBackgroundMagneticField(Bh)
        actualanswer = sin(xp * x[0]) * sin(yp * x[1]) * cos(zp * x[2])
        abserror = abs(actualanswer - model.getAnomalyPotential())
        biggesterror = sup(abserror)
        self.assertLessEqual(biggesterror, self.TESTTOL)
    def setUp(self):
        for x in [(int(mpiSize**(1 / 3.)), int(mpiSize**(1 / 3.))), (2, 3),
                  (2, 2), (1, 2), (1, 1)]:
            NX = x[0]
            NY = x[1]
            NZ = mpiSize // (x[0] * x[1])
            if NX * NY * NZ == mpiSize:
                break

        self.domain = Brick(n0=NE * NX - 1,
                            n1=NE * NY - 1,
                            n2=NE * NZ - 1,
                            l0=1.,
                            l1=1.,
                            l2=1.,
                            d0=NX,
                            d1=NY,
                            d2=NZ)
        self.order = 1
Beispiel #15
0
 def setUp(self):
     self.domain = Brick(n0=NE * NXb - 1,
                         n1=NE * NYb - 1,
                         n2=NE * NZb - 1,
                         l0=1.,
                         l1=1.,
                         l2=1.,
                         d0=NXb,
                         d1=NYb,
                         d2=NZb)
     self.functionspaces = [
         ContinuousFunction(self.domain),
         Function(self.domain),
         ReducedFunction(self.domain),
         FunctionOnBoundary(self.domain),
         ReducedFunctionOnBoundary(self.domain)
     ]
     #We aren't testing DiracDeltaFunctions
     self.xn = 5  # number of grids on x axis
     self.yn = 5  # number of grids on y axis
     self.zn = 5
Beispiel #16
0
 def setUp(self):
     Stations = [ (0.,0.,0.), (1.,0,0.), (0,1,0.), (1,1,0.) ]
     StationsTags = ["A1", "A2", "A3", "A4" ]
     self.domain=Brick(n0=5,n1=5,n2=5,diracPoints=Stations,diracTags=StationsTags)
Beispiel #17
0
 def setUp(self):
     self.domain = Brick(10, 10, 10)
Beispiel #18
0

if __name__ == "__main__":
    try:
        from esys.ripley import Brick
        HAVE_RIPLEY = True
    except ImportError:
        HAVE_RIPLEY = False
        print("Ripley module not available")

    if HAVE_RIPLEY:
        from esys.escript import *
        from esys.escript.linearPDEs import Poisson
        from esys.weipa import saveSilo, saveVoxet

        dom = Brick(l0=1.,l1=1.,n0=9, n1=9, n2=9)
        x = dom.getX()
        gammaD = whereZero(x[0])+whereZero(x[1])
        pde = Poisson(dom)
        q = gammaD
        pde.setValue(f=1, q=q)
        u = pde.getSolution()
        u=interpolate(u+dom.getX()[2], ReducedFunction(dom))
        print(u)
        saveVoxet('/tmp/poisson.vo', u=u)
        print("-------")
        dom = Brick(l0=1.,l1=1.,l2=4.,n0=18, n1=18, n2=36)
        v=readVoxet(dom, '/tmp/poisson.vo', 'u', fillValue=0.5)
        print(v)
        #saveSilo('/tmp/poisson', v=v)
 def setUp(self):
     self.domain = Brick(n0=NE0*NXb-1, n1=NE1*NYb-1, n2=NE2*NZb-1, d0=NXb, d1=NYb, d2=NZb)
     self.package = SolverOptions.PASO
     self.method = SolverOptions.BICGSTAB
     self.preconditioner = SolverOptions.JACOBI
Beispiel #20
0
            d0 = d0 * f
            d2 = d2 / f
        elif (NY+1)%(d1*f) == 0:
            d1 = d1 * f
            d2 = d2 / f
    else:
        if (NY+1)%(d1*f) == 0:
            d1 = d1 * f
            d2 = d2 / f
        elif (NX+1)%(d0*f) == 0:
            d0 = d0 * f
            d2 = d2 / f

# create domain
print("Domain subdivisions: %d x %d x %d"%(d0,d1,d2))
dom = Brick(NX, NY, n_cells_v, l0, l1, l2, d0, d1, d2)

dom_len = [sup(dom.getX()[i])-inf(dom.getX()[i]) for i in range(dom.getDim())]

# report domain setup
print("Domain size: "+str([NX, NY, n_cells_v]))
print("     length: "+str(dom_len))
print("     origin: "+str(dom_origin))

DIM = dom.getDim() # = 3

datacoords = ReducedFunction(dom).getX()

# create the output directory if not existing already
try:
    os.mkdir(OUTPUTDIR)
            rg.append((mid_point, receiver_line[iy]))
    #
    # create domain:
    #
    if DIM == 2:
        domain = Rectangle(ne_x,
                           ne_z,
                           l0=width_x,
                           l1=depth,
                           diracPoints=src_locations,
                           diracTags=src_tags)
    else:
        domain = Brick(ne_x,
                       ne_x,
                       ne_z,
                       l0=width_x,
                       l1=width_y,
                       l2=depth,
                       diracPoints=src_locations,
                       diracTags=src_tags)
    wl = Ricker(frq, tcenter)

    #======================================================================
    z = Function(domain).getX()[DIM - 1]
    z_bottom = 0
    v_p = 0
    delta = 0
    vareps = 0
    azmth = 0
    rho = 0
    for l in range(len(layers)):
        m = wherePositive(z -
Beispiel #22
0
if __name__ == "__main__":
    try:
        from esys.ripley import Brick
        HAVE_RIPLEY = True
    except ImportError:
        HAVE_RIPLEY = False
        print("Ripley module not available")

    if HAVE_RIPLEY:
        from esys.escript import *
        from esys.escript.linearPDEs import Poisson
        from esys.weipa import saveSilo, saveVoxet

        import tempfile

        dom = Brick(l0=1., l1=1., n0=9, n1=9, n2=9)
        x = dom.getX()
        gammaD = whereZero(x[0]) + whereZero(x[1])
        pde = Poisson(dom)
        q = gammaD
        pde.setValue(f=1, q=q)
        u = pde.getSolution()
        u = interpolate(u + dom.getX()[2], ReducedFunction(dom))
        print(u)
        handle, filename = tempfile.mkstemp(suffix='.vo', prefix='poisson')
        saveVoxet(filename, u=u)
        print("-------")
        dom = Brick(l0=1., l1=1., l2=4., n0=18, n1=18, n2=36)
        v = readVoxet(dom, filename, 'u', fillValue=0.5)
        print(v)
        os.remove(filename)
class TestDCResistivityApp(unittest.TestCase):

    dx = 10  # grid line spacing in [m]
    NEx = 50  # number of nodes in the x direction
    NEy = 50  # number of nodes in the y direction
    NEz = 50  # number of nodes in the z direction
    H0 = 600  # height [m] of transect above bottom of domain (will be locked to grid)
    sig_p = 1.  # primary conductivity
    sig_2 = 100.  # conductivity in ball    xdim = 1000.
    TESTTOL = 1e-3
    POSx = 100
    POSy = 70
    NEGx = 100
    NEGy = 110
    POS_node = (POSx * dx, POSy * dx, NEz * dx)
    NEG_node = (NEGx * dx, NEGy * dx, NEz * dx)
    Z0 = 100  # vertical position of circle below transect [m]
    Lx = dx * NEx
    Ly = dx * NEy
    Lz = dx * NEz
    c = [Lx / 2., Ly / 2., H0 - Z0]  # circle center
    R = 50.  # radius

    def setUp(self):
        self.domain = Brick(n0=self.NEx,
                            n1=self.NEy,
                            n2=self.NEz,
                            l0=self.Lx,
                            l1=self.Ly,
                            l2=self.Lz,
                            diracPoints=[self.POS_node, self.NEG_node],
                            diracTags=['e0', 'e1'])

    def tearDown(self):
        del self.domain

    def test_pde_Primary(self):

        model1 = DCResistivityModel(self.domain,
                                    sigma0=self.sig_p,
                                    useFastSolver=True)
        model1.setPrimaryPotentialForHalfSpace(
            sources=[self.POS_node, self.NEG_node], charges=[1.0, -1.0])

        analyticprimary = model1.setPrimaryPotentialForHalfSpace(
            sources=[self.POS_node, self.NEG_node], charges=[1.0, -1.0])
        primaryans1 = model1.getPrimaryPotential()
        model2 = DCResistivityModel(self.domain,
                                    sigma0=self.sig_p,
                                    useFastSolver=True)
        src = Scalar(0., DiracDeltaFunctions(self.domain))
        src.setTaggedValue('e0', 1.0)
        src.setTaggedValue('e1', -1.0)
        model2.setPrimaryPotential(source=src)
        primaryans2 = model2.getPrimaryPotential()
        abserror = abs(primaryans1 - primaryans2)
        self.assertLessEqual(sup(abserror), self.TESTTOL * 10., "primaries")
        sigma = Scalar(self.sig_p, ContinuousFunction(self.domain))
        x = self.domain.getX()
        d = length(x - self.c)
        sphereCond = sigma + (self.sig_2 - self.sig_p) * whereNegative(
            d - self.R)  # 0 for d>R and 1 for d<R
        model1.setConductivity(sphereCond)
        model2.setConductivity(sphereCond)
        us1 = model1.getSecondaryPotential()
        us2 = model1.getSecondaryPotential()
        abserror = abs(us1 - us2)
        self.assertLessEqual(sup(abserror), self.TESTTOL * 1., "secondaries")
        ut1 = model1.getPotential()
        ut2 = model2.getPotential()
        model3 = DCResistivityModelNoPrimary(self.domain,
                                             source=src,
                                             sigma=sphereCond,
                                             useFastSolver=True)
        ut3 = model3.getPotential()
        abserror = abs(ut1 - ut2)
        self.assertLessEqual(sup(abserror), self.TESTTOL * 10.,
                             "total with primaries")
        abserror = abs(ut1 - ut3)
        self.assertLessEqual(sup(abserror), self.TESTTOL * 10.,
                             "total with analytic primary")
        abserror = abs(ut2 - ut3)
        self.assertLessEqual(sup(abserror), self.TESTTOL * 10.,
                             "total with FE primary")