class DOR(BaseEnvisatFile):
    """A class for parsing Envisat DORIS orbit files"""

    def __init__(self,fileName=None):
        BaseEnvisatFile.__init__(self)
        self.fileName = fileName
        self.fp = None
        self.orbit = Orbit()
        self.orbit.setOrbitSource('DORIS')
        self.orbit.setReferenceFrame('ECR')

    def parse(self):

        orbitDict = {}
        try:
            self.fp = open(self.fileName, 'rb')
        except IOError as errs:
            errno,strerr = errs
            print("IOError: %s" % strerr)
            return

        self.readMPH()
        self.readSPH()
        self.readStateVectors()

        self.fp.close()

        if (self.sph['dataSets'][0]['DS_NAME'] == 'DORIS PRELIMINARY ORBIT'):
            self.orbit.setOrbitQuality('Preliminary')
        elif (self.sph['dataSets'][0]['DS_NAME'] == 'DORIS PRECISE ORBIT'):
            self.orbit.setOrbitQuality('Precise')

        orbitDict.update(self.mph)
        orbitDict.update(self.sph)

        return orbitDict

    def readStateVectors(self):
        headerLength = self.mphLength + self.sphLength
        self.fp.seek(headerLength)

        for line in self.fp.readlines():
            vals = line.decode('utf8').split()
            dateTime = self._parseDateTime(vals[0] + ' ' + vals[1])
            position = list(map(float,vals[4:7]))
            velocity = list(map(float,vals[7:10]))
            sv = StateVector()
            sv.setTime(dateTime)
            sv.setPosition(position)
            sv.setVelocity(velocity)
            self.orbit.addStateVector(sv)

    def _parseDateTime(self,dtString):
        dateTime = datetime.datetime.strptime(dtString,'%d-%b-%Y %H:%M:%S.%f')
        return dateTime
Exemple #2
0
    def trimOrbit(self, startTime, stopTime):
        """Trim the list of state vectors to encompass the time span [startTime:stopTime]"""

        newOrbit = Orbit()
        newOrbit.setOrbitSource('ODR')
        newOrbit.setReferenceFrame('ECR')
        for sv in self._ephemeris:
            if ((sv.getTime() > startTime) and (sv.getTime() < stopTime)):
                newOrbit.addStateVector(sv)

        return newOrbit
Exemple #3
0
class Pulsetiming(Component):

    logging_name = "isce.stdproc.pulsetiming"    

    def __init__(self):
        super(Pulsetiming, self).__init__()
        self.frame = None
        self.orbit = Orbit(source='Pulsetiming')
        return None

    def createPorts(self):
        framePort = Port(name='frame',method=self.addFrame)
        self._inputPorts.add(framePort)
        return None

    def getOrbit(self):
        return self.orbit
    
    def addFrame(self):        
        frame = self.inputPorts['frame']
        if frame:
            if isinstance(frame, Frame):
                self.frame = frame                
            else:
                self.logger.error(
                    "Object must be of type Frame, not %s" % (frame.__class__)
                    )
                raise TypeError
            pass
        return None
                 
#    @port(Frame)
#    def addFrame(self):
#        return None

    def pulsetiming(self):
        self.activateInputPorts()
                                   
        numberOfLines = self.frame.getNumberOfLines()
        prf = self.frame.getInstrument().getPulseRepetitionFrequency()
        pri = 1.0/prf
        startTime = self.frame.getSensingStart()
        thisOrbit = self.frame.getOrbit()
        self.orbit.setReferenceFrame(thisOrbit.getReferenceFrame())
        
        for i in range(numberOfLines):
            dt = i*pri
            time = startTime + datetime.timedelta(seconds=dt)
            sv = thisOrbit.interpolateOrbit(time,method='hermite')
            self.orbit.addStateVector(sv)                
Exemple #4
0
class Orbit2sch(Component):
    parameter_list = (ORBIT_POSITION, ORBIT_VELOCITY, PLANET_GM,
                      ELLIPSOID_MAJOR_SEMIAXIS, ELLIPSOID_ECCENTRICITY_SQUARED,
                      COMPUTE_PEG_INFO_FLAG, PEG_LATITUDE, PEG_LONGITUDE,
                      AVERAGE_HEIGHT, PEG_HEADING,
                      SCH_GRAVITATIONAL_ACCELERATION, SCH_POSITION,
                      SCH_VELOCITY)
    ## An imperative flag? REFACTOR.
    computePegInfoFlag = -1  #false by default

    planetGM = CN.EarthGM
    ellipsoidMajorSemiAxis = CN.EarthMajorSemiAxis
    ellipsoidEccentricitySquared = CN.EarthEccentricitySquared

    def __init__(self, averageHeight=None, planet=None, orbit=None, peg=None):

        super(Orbit2sch, self).__init__()

        self.averageHeight = averageHeight

        if planet is not None: self.wireInputPort(name='planet', object=planet)
        if orbit is not orbit: self.wireInputPort(name='orbit', object=orbit)
        if peg is not None: self.wireInputPort(name='peg', object=peg)

        self._time = None
        self._orbit = None
        self.dim1_orbitPosition = None
        self.dim2_orbitPosition = None
        self.dim1_orbitVelocity = None
        self.dim2_orbitVelocity = None

        self.dim1_position = None
        self.dim2_position = None
        self.dim1_velocity = None
        self.dim2_velocity = None
        self.dim1_acceleration = None
        self.dim2_acceleration = None
        self.logger = logging.getLogger('isce.orbit2sch')

        return

    def createPorts(self):
        # Create input ports
        orbitPort = Port(name='orbit', method=self.addOrbit)
        planetPort = Port(name='planet', method=self.addPlanet)
        pegPort = Port(name='peg', method=self.addPeg)
        # Add the ports
        self.inputPorts.add(orbitPort)
        self.inputPorts.add(planetPort)
        self.inputPorts.add(pegPort)
        return None

    def orbit2sch(self):
        for port in self.inputPorts:
            port()
        self.dim1_orbitPosition = len(self.orbitPosition)
        self.dim2_orbitPosition = len(self.orbitPosition[0])
        self.dim1_orbitVelocity = len(self.orbitVelocity)
        self.dim2_orbitVelocity = len(self.orbitVelocity[0])
        self.dim1_position = self.dim1_orbitPosition
        self.dim2_position = self.dim2_orbitPosition
        self.dim1_velocity = self.dim1_orbitVelocity
        self.dim2_velocity = self.dim2_orbitVelocity
        self.dim1_acceleration = self.dim1_orbitPosition
        self.dim2_acceleration = self.dim2_orbitPosition
        self.allocateArrays()
        self.setState()
        orbit2sch.orbit2sch_Py()
        self.getState()
        self.deallocateArrays()
        self._orbit = Orbit(source='SCH')
        #        self._orbit.setOrbitSource('Orbit2SCH')
        self._orbit.setReferenceFrame('SCH')
        #
        for i in range(len(self.position)):
            sv = StateVector()
            sv.setTime(self._time[i])
            sv.setPosition(self.position[i])
            sv.setVelocity(self.velocity[i])
            self._orbit.addStateVector(sv)
        return

    def setState(self):
        orbit2sch.setStdWriter_Py(int(self.stdWriter))
        if self.computePegInfoFlag == -1:
            orbit2sch.setPegLatitude_Py(float(self.pegLatitude))
            orbit2sch.setPegLongitude_Py(float(self.pegLongitude))
            orbit2sch.setPegHeading_Py(float(self.pegHeading))
            orbit2sch.setAverageHeight_Py(float(self.averageHeight))

        orbit2sch.setOrbitPosition_Py(self.orbitPosition,
                                      self.dim1_orbitPosition,
                                      self.dim2_orbitPosition)
        orbit2sch.setOrbitVelocity_Py(self.orbitVelocity,
                                      self.dim1_orbitVelocity,
                                      self.dim2_orbitVelocity)
        orbit2sch.setPlanetGM_Py(float(self.planetGM))
        orbit2sch.setEllipsoidMajorSemiAxis_Py(
            float(self.ellipsoidMajorSemiAxis))
        orbit2sch.setEllipsoidEccentricitySquared_Py(
            float(self.ellipsoidEccentricitySquared))
        orbit2sch.setComputePegInfoFlag_Py(int(self.computePegInfoFlag))
        return None

    def setOrbitPosition(self, var):
        self.orbitPosition = var
        return

    def setOrbitVelocity(self, var):
        self.orbitVelocity = var
        return

    def setPlanetGM(self, var):
        self.planetGM = float(var)
        return

    def setEllipsoidMajorSemiAxis(self, var):
        self.ellipsoidMajorSemiAxis = float(var)
        return

    def setEllipsoidEccentricitySquared(self, var):
        self.ellipsoidEccentricitySquared = float(var)
        return

    def setComputePegInfoFlag(self, var):
        self.computePegInfoFlag = int(var)
        return

    def setPegLatitude(self, var):
        self.pegLatitude = float(var)
        return

    def setPegLongitude(self, var):
        self.pegLongitude = float(var)
        return

    def setPegHeading(self, var):
        self.pegHeading = float(var)
        return

    def setAverageHeight(self, var):
        self.averageHeight = float(var)
        return

    def getState(self):
        self.position = orbit2sch.getSchPosition_Py(self.dim1_position,
                                                    self.dim2_position)
        self.velocity = orbit2sch.getSchVelocity_Py(self.dim1_velocity,
                                                    self.dim2_velocity)
        self.acceleration = orbit2sch.getSchGravitationalAcceleration_Py(
            self.dim1_acceleration, self.dim2_acceleration)
        return


#    def getStdWriter(self):
#        return self.position

    def getSchVelocity(self):
        return self.velocity

    def getSchGravitationalAcceleration(self):
        return self.acceleration

    def getOrbit(self):
        return self._orbit

    def allocateArrays(self):
        if self.dim1_orbitPosition is None:
            self.dim1_orbitPosition = len(self.orbitPosition)
            self.dim2_orbitPosition = len(self.orbitPosition[0])

        if (not self.dim1_orbitPosition) or (not self.dim2_orbitPosition):
            raise ValueError("Error. Trying to allocate zero size array")

        orbit2sch.allocate_xyz_Py(self.dim1_orbitPosition,
                                  self.dim2_orbitPosition)

        if self.dim1_orbitVelocity is None:
            self.dim1_orbitVelocity = len(self.orbitVelocity)
            self.dim2_orbitVelocity = len(self.orbitVelocity[0])

        if (not self.dim1_orbitVelocity) or (not self.dim2_orbitVelocity):
            raise ValueError("Error. Trying to allocate zero size array")

        orbit2sch.allocate_vxyz_Py(self.dim1_orbitVelocity,
                                   self.dim2_orbitVelocity)

        if self.dim1_position is None:
            self.dim1_position = len(self.position)
            self.dim2_position = len(self.position[0])

        if (not self.dim1_position) or (not self.dim2_position):
            ("Error. Trying to allocate zero size array")

            raise Exception

        orbit2sch.allocate_sch_Py(self.dim1_position, self.dim2_position)

        if self.dim1_velocity is None:
            self.dim1_velocity = len(self.velocity)
            self.dim2_velocity = len(self.velocity[0])

        if (not self.dim1_velocity) or (not self.dim2_velocity):
            print("Error. Trying to allocate zero size array")

            raise Exception

        orbit2sch.allocate_vsch_Py(self.dim1_velocity, self.dim2_velocity)

        if self.dim1_acceleration is None:
            self.dim1_acceleration = len(self.acceleration)
            self.dim2_acceleration = len(self.acceleration[0])

        if (not self.dim1_acceleration) or (not self.dim2_acceleration):
            print("Error. Trying to allocate zero size array")

            raise Exception

        orbit2sch.allocate_asch_Py(self.dim1_acceleration,
                                   self.dim2_acceleration)

        return

    def deallocateArrays(self):
        orbit2sch.deallocate_xyz_Py()
        orbit2sch.deallocate_vxyz_Py()
        orbit2sch.deallocate_sch_Py()
        orbit2sch.deallocate_vsch_Py()
        orbit2sch.deallocate_asch_Py()

        return

    @property
    def orbit(self):
        return self._orbit

    @orbit.setter
    def orbit(self, orbit):
        self.orbit = orbit
        return None

    @property
    def time(self):
        return self._time

    @time.setter
    def time(self, time):
        self.time = time
        return None

    def addOrbit(self):
        orbit = self.inputPorts['orbit']
        if orbit:
            try:
                time, self.orbitPosition, self.orbitVelocity, offset = orbit.to_tuple(
                )
                self._time = []
                for t in time:
                    self._time.append(offset + datetime.timedelta(seconds=t))
            except AttributeError:
                self.logger.error(
                    "orbit port should look like an orbit, not: %s" %
                    (orbit.__class__))
                raise AttributeError
            pass
        return None

    def addPlanet(self):
        planet = self._inputPorts.getPort('planet').getObject()
        if (planet):
            try:
                self.planetGM = planet.get_GM()
                self.ellipsoidMajorSemiAxis = planet.get_elp().get_a()
                self.ellipsoidEccentricitySquared = planet.get_elp().get_e2()
            except AttributeError:
                self.logger.error(
                    "Object %s requires get_GM(), get_elp().get_a() and get_elp().get_e2() methods"
                    % (planet.__class__))
                raise AttributeError

    def addPeg(self):
        peg = self._inputPorts.getPort('peg').getObject()
        if (peg):
            try:
                self.pegLatitude = math.radians(peg.getLatitude())
                self.pegLongitude = math.radians(peg.getLongitude())
                self.pegHeading = math.radians(peg.getHeading())
                self.logger.debug("Peg Object: %s" % (str(peg)))
            except AttributeError:
                self.logger.error(
                    "Object %s requires getLatitude(), getLongitude() and getHeading() methods"
                    % (peg.__class__))
                raise AttributeError

            pass
        pass

    pass
Exemple #5
0
class ODR(object):
    """A class to parse Orbital Data Records (ODR) generated by Delft"""

    logging_name = 'isceobj.Orbit.ODR'

    @logged
    def __init__(self, file=None):
        self._file = file
        self._format = None
        self._satellite = None
        self._arcNumber = None
        self._cycleLength = None
        self._numberOfRecords = None
        self._version = None
        self._ephemeris = Orbit()
        self._ephemeris.setOrbitSource('ODR')
        self._ephemeris.setReferenceFrame('ECR')
        self.grs80 = Ellipsoid.Ellipsoid(
            *AstronomicalHandbook.PlanetsData.ellipsoid['Earth']['GRS-80'])

        return None

    #jng added the start and stop time. The computation of the velocities seems pretty time comsuming, so limit the orbit data extraction only to startTime nad stopTime
    def parseHeader(self, startTime=None, stopTime=None):
        fp = None
        try:
            fp = open(self._file, 'rb')
        except IOError as strerr:
            self.logger.error(strerr)
        buffer = fp.read(16)
        # Header 1
        (format, satellite,
         dataStartTimeSeconds) = struct.unpack('>4s8si', buffer)
        buffer = fp.read(16)
        # Header 2
        (cycleLength, number, numberOfRecords,
         version) = struct.unpack('>4i', buffer)

        self._format = format.decode('utf-8')
        self._satellite = satellite.decode('utf-8')
        self._arcNumber = number
        self._cycleLength = cycleLength * 1e3  # In cycle length in days
        self._numberOfRecords = numberOfRecords
        self._version = version

        positions = []
        for i in range(numberOfRecords):
            buffer = fp.read(16)
            if not startTime == None:
                position = self.parseDataRecords(buffer)
                if position['time'] < startTime:
                    continue

            if not stopTime == None:
                position = self.parseDataRecords(buffer)
                if position['time'] > stopTime:
                    continue

            positions.append(self.parseDataRecords(buffer))

        self.createStateVectors(positions)
        fp.close()

    def parseDataRecords(self, buffer):
        """Parse the individual data records for this ODR file"""
        (timeSeconds, latitude, longitude,
         height) = struct.unpack('>4i', buffer)
        time = self._utcSecondsToDatetime(timeSeconds)
        if (self._format == '@ODR'):
            latitude = latitude * 1e-6
            longitude = longitude * 1e-6
        elif (self._format == 'xODR'):
            latitude = latitude * 1e-7
            longitude = longitude * 1e-7
        height = height * 1e-3

        xyz = self._convertToXYZ(latitude, longitude, height)
        return ({'time': time, 'x': xyz[0], 'y': xyz[1], 'z': xyz[2]})

    def createStateVectors(self, positions):
        """Calculate the satellite velocity from the position data and create StateVector objects"""

        for i in range(len(positions)):
            t0 = positions[i]['time']
            x0 = positions[i]['x']
            y0 = positions[i]['y']
            z0 = positions[i]['z']

            sv = StateVector()
            sv.setTime(t0)
            sv.setPosition([x0, y0, z0])
            sv.setVelocity([0.0, 0.0, 0.0])
            self._ephemeris.addStateVector(sv)
        self._calculateVelocities()

    def _calculateVelocities(self):
        for sv in self._ephemeris:
            t0 = sv.getTime()
            t1 = t0 + datetime.timedelta(seconds=-0.5)
            t2 = t0 + datetime.timedelta(seconds=0.5)
            try:
                sv1 = self._ephemeris.interpolateOrbit(t1, method='legendre')
                sv2 = self._ephemeris.interpolateOrbit(t2, method='legendre')
            except ValueError:
                continue
            if (not sv1) or (not sv2):
                continue
            v1 = sv1.getPosition()
            v2 = sv2.getPosition()
            vx = (v2[0] - v1[0])
            vy = (v2[1] - v1[1])
            vz = (v2[2] - v1[2])
            sv.setVelocity([vx, vy, vz])

    def trimOrbit(self, startTime, stopTime):
        """Trim the list of state vectors to encompass the time span [startTime:stopTime]"""

        newOrbit = Orbit()
        newOrbit.setOrbitSource('ODR')
        newOrbit.setReferenceFrame('ECR')
        for sv in self._ephemeris:
            if ((sv.getTime() > startTime) and (sv.getTime() < stopTime)):
                newOrbit.addStateVector(sv)

        return newOrbit

    def getEphemeris(self):
        return self._ephemeris

    def _convertToXYZ(self, latitude, longitude, height):
        # The latitude, longitude and height are referenced to the center of mass of the satellite above the GRS80 ellipsoid
        xyz = self.grs80.llh_to_xyz([latitude, longitude, height])
        return xyz

    def _utcSecondsToDatetime(self, seconds):
        """All of the ODR records are in UTC seconds from 1 Jan. 1985"""
        dataTime = datetime.datetime(year=1985, month=1, day=1)
        dataTime = dataTime + datetime.timedelta(seconds=seconds)
        return dataTime
Exemple #6
0
class Sch2orbit(Component):

    planetGM = CN.EarthGM
    ellipsoidMajorSemiAxis = CN.EarthMajorSemiAxis
    ellipsoidEccentricitySquared = CN.EarthEccentricitySquared

    def __init__(self, averageHeight=None, planet=None, orbit=None, peg=None):

        super(Sch2orbit, self).__init__()

        self.averageHeight = averageHeight

        if planet is not None: self.wireInputPort(name='planet', object=planet)
        if orbit is not orbit: self.wireInputPort(name='orbit', object=orbit)
        if peg is not None: self.wireInputPort(name='peg', object=peg)

        self._numVectors = None
        self._time = None
        self._orbit = None

        self.position = []
        self.velocity = []
        self.acceleration = []
        self.logger = logging.getLogger('isce.sch2orbit')
        self.dictionaryOfOutputVariables = {
            'XYZ_POSITION': 'self.position',
            'XYZ_VELOCITY': 'self.velocity',
            'XYZ_GRAVITATIONAL_ACCELERATION': 'self.acceleration'
        }
        return

    def createPorts(self):
        # Create input ports
        orbitPort = Port(name='orbit', method=self.addOrbit)
        planetPort = Port(name='planet', method=self.addPlanet)
        pegPort = Port(name='peg', method=self.addPeg)
        # Add the ports
        self.inputPorts.add(orbitPort)
        self.inputPorts.add(planetPort)
        self.inputPorts.add(pegPort)
        return None

    def sch2orbit(self):
        for port in self.inputPorts:
            port()

        lens = [len(self.orbitPosition), len(self.orbitVelocity)]
        if min(lens) != max(lens):
            raise Exception('Position and Velocity vector lengths dont match')

        self._numVectors = lens[0]

        self.allocateArrays()
        self.setState()
        sch2orbit.sch2orbit_Py()
        self.getState()
        self.deallocateArrays()
        self._orbit = Orbit(source='XYZ')
        self._orbit.setReferenceFrame('XYZ')
        #
        for i in range(len(self.position)):
            sv = StateVector()
            sv.setTime(self._time[i])
            sv.setPosition(self.position[i])
            sv.setVelocity(self.velocity[i])
            self._orbit.addStateVector(sv)
        return

    def setState(self):
        sch2orbit.setStdWriter_Py(int(self.stdWriter))
        sch2orbit.setPegLatitude_Py(float(self.pegLatitude))
        sch2orbit.setPegLongitude_Py(float(self.pegLongitude))
        sch2orbit.setPegHeading_Py(float(self.pegHeading))
        sch2orbit.setRadiusOfCurvature_Py(float(self.radiusOfCurvature))

        sch2orbit.setOrbitPosition_Py(self.orbitPosition, self._numVectors)
        sch2orbit.setOrbitVelocity_Py(self.orbitVelocity, self._numVectors)
        sch2orbit.setPlanetGM_Py(float(self.planetGM))
        sch2orbit.setEllipsoidMajorSemiAxis_Py(
            float(self.ellipsoidMajorSemiAxis))
        sch2orbit.setEllipsoidEccentricitySquared_Py(
            float(self.ellipsoidEccentricitySquared))
        return None

    def setOrbitPosition(self, var):
        self.orbitPosition = var
        return

    def setOrbitVelocity(self, var):
        self.orbitVelocity = var
        return

    def setPlanetGM(self, var):
        self.planetGM = float(var)
        return

    def setEllipsoidMajorSemiAxis(self, var):
        self.ellipsoidMajorSemiAxis = float(var)
        return

    def setEllipsoidEccentricitySquared(self, var):
        self.ellipsoidEccentricitySquared = float(var)
        return

    def setPegLatitude(self, var):
        self.pegLatitude = float(var)
        return

    def setPegLongitude(self, var):
        self.pegLongitude = float(var)
        return

    def setPegHeading(self, var):
        self.pegHeading = float(var)
        return

    def setRadiusOfCurvature(self, var):
        self.radiusOfCurvature = float(var)
        return

    def getState(self):
        self.position = sch2orbit.getXYZPosition_Py(self._numVectors)
        self.velocity = sch2orbit.getXYZVelocity_Py(self._numVectors)
        self.acceleration = sch2orbit.getXYZGravitationalAcceleration_Py(
            self._numVectors)
        return

    def getXYZVelocity(self):
        return self.velocity

    def getXYZGravitationalAcceleration(self):
        return self.acceleration

    def getOrbit(self):
        return self._orbit

    def allocateArrays(self):
        if (not self._numVectors):
            raise ValueError("Error. Trying to allocate zero size array")

        sch2orbit.allocateArrays_Py(self._numVectors)

        return

    def deallocateArrays(self):
        sch2orbit.deallocateArrays_Py()

        return

    @property
    def orbit(self):
        return self._orbit

    @orbit.setter
    def orbit(self, orbit):
        self.orbit = orbit
        return None

    @property
    def time(self):
        return self._time

    @time.setter
    def time(self):
        self.time = time
        return None

    def addOrbit(self):
        orbit = self.inputPorts['orbit']
        if orbit:
            try:
                time, self.orbitPosition, self.orbitVelocity, offset = orbit.to_tuple(
                )
                self._time = []
                for t in time:
                    self._time.append(offset + datetime.timedelta(seconds=t))
            except AttributeError:
                self.logger.error(
                    "orbit port should look like an orbit, not: %s" %
                    (orbit.__class__))
                raise AttributeError
            pass
        return None

    def addPlanet(self):
        planet = self._inputPorts.getPort('planet').getObject()
        if (planet):
            try:
                self.planetGM = planet.get_GM()
                self.ellipsoidMajorSemiAxis = planet.get_elp().get_a()
                self.ellipsoidEccentricitySquared = planet.get_elp().get_e2()
            except AttributeError:
                self.logger.error(
                    "Object %s requires get_GM(), get_elp().get_a() and get_elp().get_e2() methods"
                    % (planet.__class__))
                raise AttributeError

    def addPeg(self):
        peg = self._inputPorts.getPort('peg').getObject()
        if (peg):
            try:
                self.pegLatitude = math.radians(peg.getLatitude())
                self.pegLongitude = math.radians(peg.getLongitude())
                self.pegHeading = math.radians(peg.getHeading())
                self.logger.debug("Peg Object: %s" % (str(peg)))
            except AttributeError:
                self.logger.error(
                    "Object %s requires getLatitude(), getLongitude() and getHeading() methods"
                    % (peg.__class__))
                raise AttributeError

            pass
        pass

    pass