5 from numpy.testing 
import assert_allclose, assert_array_equal
 
    7 from .channel 
import Channel
 
    8 from .fitsChan 
import FitsChan
 
    9 from .polyMap 
import PolyMap
 
   10 from .xmlChan 
import XmlChan
 
   11 from .stream 
import StringStream
 
   15     """Base class for unit tests of objects 
   19         """Assert that two astshim objects are identical. 
   21         Identical means the objects are of the same class (if checkType) 
   22         and all properties are identical (including whether set or defaulted). 
   25             self.assertIs(
type(obj1), 
type(obj2))
 
   26         self.assertEqual(obj1.show(), obj2.show())
 
   27         self.assertEqual(str(obj1), str(obj2))
 
   28         self.assertEqual(repr(obj1), repr(obj2))
 
   31         """Check that an astshim object can be deep-copied 
   33         nobj = obj.getNObject()
 
   34         nref = obj.getRefCount()
 
   40         for cp 
in copyIter(obj):
 
   42             self.assertEqual(obj.getNObject(), nobj + 1)
 
   45             self.assertEqual(obj.getRefCount(), nref)
 
   46             self.assertFalse(obj.same(cp))
 
   47             self.assertEqual(cp.getNObject(), nobj + 1)
 
   48             self.assertEqual(cp.getRefCount(), 1)
 
   50             originalIdent = obj.ident
 
   51             cp.ident = obj.ident + 
" modified" 
   52             self.assertEqual(obj.ident, originalIdent)
 
   55         self.assertEqual(obj.getNObject(), nobj)
 
   56         self.assertEqual(obj.getRefCount(), nref)
 
   59         """Check that an astshim object can be persisted and unpersisted 
   61         @param[in] obj  Object to be checked 
   62         @param[in] typeFromChannel  Type of object expected to be read from 
   63                         a channel (since some thin wrapper types are read 
   64                         as the underlying type); None if the original type 
   66         Check persistence using Channel, FitsChan (with native encoding, 
   67         as the only encoding compatible with all AST objects), XmlChan 
   70         for channelType, options 
in (
 
   72             (FitsChan, 
"Encoding=Native"),
 
   76             chan = channelType(ss, options)
 
   79             if channelType 
is FitsChan:
 
   81             obj_copy = chan.read()
 
   82             if typeFromChannel 
is not None:
 
   83                 self.assertIs(
type(obj_copy), typeFromChannel)
 
   88         obj_copy = pickle.loads(pickle.dumps(obj))
 
   94     """Base class for unit tests of mappings 
   98         """Check that a mapping's reverse transform is the opposite of forward 
  100         amap is the mapping to test 
  101         poslist is a list of input position for a forward transform; 
  102             a numpy array with shape [nin, num points] 
  103             or collection that can be cast to same 
  104         rtol is the relative tolerance for numpy.testing.assert_allclose 
  105         atol is the absolute tolerance for numpy.testing.assert_allclose 
  107         poslist = np.array(poslist, dtype=float)
 
  108         if len(poslist.shape) == 1:
 
  110             poslist.shape = (1, len(poslist))
 
  112         to_poslist = amap.applyForward(poslist)
 
  113         rt_poslist = amap.applyInverse(to_poslist)
 
  114         assert_allclose(poslist, rt_poslist, rtol=rtol, atol=atol)
 
  117         amapinv = amap.inverted()
 
  118         rt2_poslist = amapinv.applyForward(to_poslist)
 
  119         assert_allclose(poslist, rt2_poslist, rtol=rtol, atol=atol)
 
  122         acmp = amap.then(amapinv)
 
  123         assert_allclose(poslist, acmp.applyForward(poslist), rtol=rtol, atol=atol)
 
  126         posvec = 
list(poslist.flat)
 
  127         to_posvec = amap.applyForward(posvec)
 
  130         assert_allclose(to_posvec, 
list(to_poslist.flat), rtol=rtol, atol=atol)
 
  132         rt_posvec = amap.applyInverse(to_posvec)
 
  133         assert_allclose(posvec, rt_posvec, rtol=rtol, atol=atol)
 
  136         """Check basic simplfication for a reversible mapping 
  139         - A compound mapping of a amap and its inverse simplifies to 
  141         - A compound mapping of a amap and a unit amap simplifies to 
  144         amapinv = amap.inverted()
 
  145         cmp1 = amap.then(amapinv)
 
  146         unit1 = cmp1.simplified()
 
  147         self.assertEqual(unit1.className, 
"UnitMap")
 
  148         self.assertEqual(amap.nIn, cmp1.nIn)
 
  149         self.assertEqual(amap.nIn, cmp1.nOut)
 
  150         self.assertEqual(cmp1.nIn, unit1.nIn)
 
  151         self.assertEqual(cmp1.nOut, unit1.nOut)
 
  153         cmp2 = amapinv.then(amap)
 
  154         unit2 = cmp2.simplified()
 
  155         self.assertEqual(unit2.className, 
"UnitMap")
 
  156         self.assertEqual(amapinv.nIn, cmp2.nIn)
 
  157         self.assertEqual(amapinv.nIn, cmp2.nOut)
 
  158         self.assertEqual(cmp2.nIn, unit2.nIn)
 
  159         self.assertEqual(cmp2.nOut, unit2.nOut)
 
  161         for ma, mb, desmap3 
in (
 
  164             (unit2, amapinv, amapinv),
 
  165             (amapinv, unit1, amapinv),
 
  168             cmp3simp = cmp3.simplified()
 
  169             self.assertEqual(cmp3simp.className, amap.simplified().className)
 
  170             self.assertEqual(ma.nIn, cmp3.nIn)
 
  171             self.assertEqual(mb.nOut, cmp3.nOut)
 
  172             self.assertEqual(cmp3.nIn, cmp3simp.nIn)
 
  173             self.assertEqual(cmp3.nOut, cmp3simp.nOut)
 
  176         """Check that a mapping gives identical answers to unpersisted copy 
  178         poslist is a list of input position for a forward transform 
  179             (if it exists), or the inverse transform (if not). 
  180             A numpy array with shape [nAxes, num points] 
  181             or collection that can be cast to same 
  183         Checks each direction, if present. However, for generality, 
  184         does not check that the two directions are inverses of each other; 
  185         call checkRoundTrip for that. 
  187         Does everything checkPersistence does, so no need to call both. 
  189         for channelType, options 
in (
 
  191             (FitsChan, 
"Encoding=Native"),
 
  198             amap_copy = chan.read()
 
  199             self.assertEqual(amap.className, amap_copy.className)
 
  200             self.assertEqual(amap.show(), amap_copy.show())
 
  201             self.assertEqual(str(amap), str(amap_copy))
 
  202             self.assertEqual(repr(amap), repr(amap_copy))
 
  205                 outPoslist = amap.applyForward(poslist)
 
  206                 assert_array_equal(outPoslist, amap_copy.applyForward(poslist))
 
  209                     assert_array_equal(amap.applyInverse(outPoslist),
 
  210                                        amap_copy.applyInverse(outPoslist))
 
  212             elif amap.hasInverse:
 
  213                 assert_array_equal(amap.applyInverse(poslist),
 
  214                                    amap_copy.applyInverse(poslist))
 
  217                 raise RuntimeError(
"mapping has neither forward nor inverse transform")
 
  220         """Check the memory usage for a compoundObject 
  222         obj1: first object in compound object 
  223         obj2: second object in compound object 
  224         cmpObj: compound object (SeriesMap, ParallelMap, CmpMap or CmpFrame) 
  225         isSeries: is compound object in series? None to not test 
  230         deltaObj = 2 
if type(obj1) == 
type(obj2) 
else 1
 
  232         initialNumObj1 = obj1.getNObject()
 
  233         initialNumObj2 = obj2.getNObject()
 
  234         initialNumCmpObj = cmpObj.getNObject()
 
  235         initialRefCountObj1 = obj1.getRefCount()
 
  236         initialRefCountObj2 = obj2.getRefCount()
 
  237         initialRefCountCmpObj = cmpObj.getRefCount()
 
  238         self.assertEqual(obj1.getNObject(), initialNumObj1)
 
  239         self.assertEqual(obj2.getNObject(), initialNumObj2)
 
  240         if isSeries 
is not None:
 
  242                 self.assertTrue(cmpObj.series)
 
  243             elif isSeries 
is False:
 
  244                 self.assertFalse(cmpObj.series)
 
  249         self.assertEqual(cmpObj.getRefCount(), initialRefCountCmpObj)
 
  250         self.assertEqual(cmpObj.getNObject(), initialNumCmpObj + 1)
 
  251         self.assertEqual(obj1.getRefCount(), initialRefCountObj1)
 
  252         self.assertEqual(obj2.getRefCount(), initialRefCountObj2)
 
  253         self.assertEqual(obj1.getNObject(), initialNumObj1 + deltaObj)
 
  254         self.assertEqual(obj2.getNObject(), initialNumObj2 + deltaObj)
 
  258         self.assertEqual(cmpObj.getRefCount(), initialRefCountCmpObj)
 
  259         self.assertEqual(cmpObj.getNObject(), initialNumCmpObj)
 
  260         self.assertEqual(obj1.getRefCount(), initialRefCountObj1)
 
  261         self.assertEqual(obj1.getNObject(), initialNumObj1)
 
  262         self.assertEqual(obj2.getRefCount(), initialRefCountObj2)
 
  263         self.assertEqual(obj2.getNObject(), initialNumObj2)
 
  267     """Make an array of coefficients for astshim.PolyMap for the following 
  270     fj(x) = C0j x0^2 + C1j x1^2 + C2j x2^2 + ... + CNj xN^2 
  272     * i ranges from 0 to N=nIn-1 
  273     * j ranges from 0 to nOut-1, 
  274     * Cij = 0.001 (i+j+1) 
  278     for out_ind 
in range(nOut):
 
  279         coeffOffset = baseCoeff * out_ind
 
  280         for in_ind 
in range(nIn):
 
  281             coeff = baseCoeff * (in_ind + 1) + coeffOffset
 
  282             coeffArr = [coeff, out_ind + 1] + [2 
if i == in_ind 
else 0 
for i 
in range(nIn)]
 
  283             forwardCoeffs.append(coeffArr)
 
  284     return np.array(forwardCoeffs, dtype=float)
 
  288     """Make an astshim.PolyMap suitable for testing 
  290     The forward transform is as follows: 
  291     fj(x) = C0j x0^2 + C1j x1^2 + C2j x2^2 + ... 
  292             + CNj xN^2 where Cij = 0.001 (i+j+1) 
  294     The reverse transform is the same equation with i and j reversed 
  295     thus it is NOT the inverse of the forward direction, 
  296     but is something that can be easily evaluated. 
  298     The equation is chosen for the following reasons: 
  299     - It is well defined for any positive value of nIn, nOut. 
  300     - It stays small for small x, to avoid wraparound of angles for 
  301       SpherePoint endpoints. 
  305     polyMap = PolyMap(forwardCoeffs, reverseCoeffs)
 
  306     assert polyMap.nIn == nIn
 
  307     assert polyMap.nOut == nOut
 
  308     assert polyMap.hasForward
 
  309     assert polyMap.hasInverse
 
  314     """Make an astshim.PolyMap suitable for testing 
  316     The forward transform is the same as for `makeTwoWayPolyMap`. 
  317     This map does not have a reverse transform. 
  319     The equation is chosen for the following reasons: 
  320     - It is well defined for any positive value of nIn, nOut. 
  321     - It stays small for small x, to avoid wraparound of angles for 
  322       SpherePoint endpoints. 
  325     polyMap = PolyMap(forwardCoeffs, nOut, 
"IterInverse=0")
 
  326     assert polyMap.nIn == nIn
 
  327     assert polyMap.nOut == nOut
 
  328     assert polyMap.hasForward
 
  329     assert not polyMap.hasInverse