Exemplo n.º 1
0
    def process(self, df):
        output = self.accumulator.identity()

        datasetFull = df['dataset']
        dataset = datasetFull.replace('_2016', '')

        isData = 'Data' in dataset

        year = 2016
        yearStr = "2016"
        muTrigger = df['HLT_IsoMu24'] | df['HLT_IsoTkMu24']
        eleTrigger = df['HLT_Ele27_WPTight_Gsf']
        photonBitMapName = 'Photon_cutBased'

        #### These are already applied in the skim
        #         filters = (df['Flag_goodVertices'] &
        #                    df['Flag_globalSuperTightHalo2016Filter'] &
        #                    df['Flag_HBHENoiseFilter'] &
        #                    df['Flag_HBHENoiseIsoFilter'] &
        #                    df['Flag_EcalDeadCellTriggerPrimitiveFilter'] &
        #                    df['Flag_BadPFMuonFilter']
        #                   )
        #         if year > 2016:
        #             filters = (filters &
        #                        df['Flag_ecalBadCalibFilterV2']
        #                       )

        muons = JaggedCandidateArray.candidatesfromcounts(
            df['nMuon'],
            pt=df['Muon_pt'],
            eta=df['Muon_eta'],
            phi=df['Muon_phi'],
            mass=df['Muon_mass'],
            charge=df['Muon_charge'],
            relIso=df['Muon_pfRelIso04_all'],
            tightId=df['Muon_tightId'],
            isPFcand=df['Muon_isPFcand'],
            isTracker=df['Muon_isTracker'],
            isGlobal=df['Muon_isGlobal'],
        )

        electrons = JaggedCandidateArray.candidatesfromcounts(
            df['nElectron'],
            pt=df['Electron_pt'],
            eta=df['Electron_eta'],
            phi=df['Electron_phi'],
            mass=df['Electron_mass'],
            charge=df['Electron_charge'],
            cutBased=df['Electron_cutBased'],
            d0=df['Electron_dxy'],
            dz=df['Electron_dz'],
        )

        jets = JaggedCandidateArray.candidatesfromcounts(
            df['nJet'],
            pt=df['Jet_pt'],
            eta=df['Jet_eta'],
            phi=df['Jet_phi'],
            mass=df['Jet_mass'],
            jetId=df['Jet_jetId'],
            btag=df['Jet_btagDeepB'],
            hadFlav=df['Jet_hadronFlavour']
            if not isData else np.ones_like(df['Jet_jetId']),
            genIdx=df['Jet_genJetIdx']
            if not isData else np.ones_like(df['Jet_jetId']),
        )

        photons = JaggedCandidateArray.candidatesfromcounts(
            df['nPhoton'],
            pt=df['Photon_pt'],
            eta=df['Photon_eta'],
            phi=df['Photon_phi'],
            mass=np.zeros_like(df['Photon_pt']),
            isEE=df['Photon_isScEtaEE'],
            isEB=df['Photon_isScEtaEB'],
            photonId=df[photonBitMapName],
            passEleVeto=df['Photon_electronVeto'],
            pixelSeed=df['Photon_pixelSeed'],
            sieie=df['Photon_sieie'],
            chIso=df['Photon_pfRelIso03_chg'] * df['Photon_pt'],
            vidCuts=df['Photon_vidNestedWPBitmap'],
            genFlav=df['Photon_genPartFlav']
            if not isData else np.ones_like(df['Photon_electronVeto']),
            genIdx=df['Photon_genPartIdx']
            if not isData else np.ones_like(df['Photon_electronVeto']),
        )
        if not isData:
            genPart = JaggedCandidateArray.candidatesfromcounts(
                df['nGenPart'],
                pt=df['GenPart_pt'],
                eta=df['GenPart_eta'],
                phi=df['GenPart_phi'],
                mass=df['GenPart_mass'],
                pdgid=df['GenPart_pdgId'],
                motherIdx=df['GenPart_genPartIdxMother'],
                status=df['GenPart_status'],
                statusFlags=df['GenPart_statusFlags'],
            )

            genmotherIdx = genPart.motherIdx
            genpdgid = genPart.pdgid

        ## TTbar vs TTGamma Overlap Removal (work in progress, still buggy)
        doOverlapRemoval = False
        if 'TTbar' in dataset:
            doOverlapRemoval = True
            overlapPt = 10.
            overlapEta = 5.
            overlapDR = 0.1
        if re.search("^W[1234]jets$", dataset):
            doOverlapRemoval = True
            overlapPt = 10.
            overlapEta = 2.5
            overlapDR = 0.05
        if 'DYjetsM' in dataset:
            doOverlapRemoval = True
            overlapPt = 15.
            overlapEta = 2.6
            overlapDR = 0.05

        if doOverlapRemoval:
            overlapPhoSelect = ((genPart.pt >= overlapPt) &
                                (abs(genPart.eta) < overlapEta) &
                                (genPart.pdgid == 22) & (genPart.status == 1))

            OverlapPhotons = genPart[overlapPhoSelect]

            idx = OverlapPhotons.motherIdx
            maxParent = maxHistoryPDGID(idx.content, idx.starts, idx.stops,
                                        genpdgid.content, genpdgid.starts,
                                        genpdgid.stops, genmotherIdx.content,
                                        genmotherIdx.starts,
                                        genmotherIdx.stops)

            isNonPrompt = (maxParent > 37).any()

            finalGen = genPart[(
                (genPart.status == 1) | (genPart.status == 71)) & ~(
                    (abs(genPart.pdgid) == 12) | (abs(genPart.pdgid) == 14) |
                    (abs(genPart.pdgid) == 16))]

            genPairs = OverlapPhotons['p4'].cross(finalGen['p4'], nested=True)
            ##remove the case where the cross produce is the gen photon with itself
            genPairs = genPairs[~(genPairs.i0 == genPairs.i1)]

            dRPairs = genPairs.i0.delta_r(genPairs.i1)

            isOverlap = ((dRPairs.min() > overlapDR) & (maxParent < 37)).any()
            passOverlapRemoval = ~isOverlap
        else:
            passOverlapRemoval = np.ones_like(df['event']) == 1

        muonSelectTight = ((muons.pt > 30) & (abs(muons.eta) < 2.4) &
                           (muons.tightId) & (muons.relIso < 0.15))

        muonSelectLoose = ((muons.pt > 15) & (abs(muons.eta) < 2.4) &
                           ((muons.isPFcand) &
                            (muons.isTracker | muons.isGlobal)) &
                           (muons.relIso < 0.25) & np.invert(muonSelectTight))

        eleEtaGap = (abs(electrons.eta) < 1.4442) | (abs(electrons.eta) >
                                                     1.566)
        elePassD0 = ((abs(electrons.eta) < 1.479) & (abs(electrons.d0) < 0.05)
                     | (abs(electrons.eta) > 1.479) &
                     (abs(electrons.d0) < 0.1))
        elePassDZ = ((abs(electrons.eta) < 1.479) & (abs(electrons.dz) < 0.1) |
                     (abs(electrons.eta) > 1.479) & (abs(electrons.dz) < 0.2))

        electronSelectTight = ((electrons.pt > 35) & (abs(electrons.eta) < 2.1)
                               & eleEtaGap & (electrons.cutBased >= 4)
                               & elePassD0 & elePassDZ)

        electronSelectLoose = ((electrons.pt > 15) & (abs(electrons.eta) < 2.4)
                               & eleEtaGap & (electrons.cutBased >= 1)
                               & elePassD0 & elePassDZ
                               & np.invert(electronSelectTight))

        tightMuon = muons[muonSelectTight]
        looseMuon = muons[muonSelectLoose]

        tightElectron = electrons[electronSelectTight]
        looseElectron = electrons[electronSelectLoose]

        oneMuon = (tightMuon.counts == 1)
        muVeto = (tightMuon.counts == 0)
        oneEle = (tightElectron.counts == 1)
        eleVeto = (tightElectron.counts == 0)
        looseMuonSel = (looseMuon.counts == 0)
        looseElectronSel = (looseElectron.counts == 0)

        #### Calculate deltaR between photon and nearest muon
        ####### make combination pairs
        phoMu = photons['p4'].cross(tightMuon['p4'], nested=True)

        ####### check delta R of each combination, if min is >0.1 it is okay, or if there are no tight muons it passes
        dRphomu = (phoMu.i0.delta_r(phoMu.i1) > 0.4).all() | (tightMuon.counts
                                                              == 0)
        phoEle = photons['p4'].cross(tightElectron['p4'], nested=True)
        dRphoele = ((phoEle.i0.delta_r(phoEle.i1)).min() >
                    0.4) | (tightElectron.counts == 0)

        #photon selection (no ID requirement used here)
        photonSelect = ((photons.pt > 20) & (abs(photons.eta) < 1.4442) &
                        (photons.isEE | photons.isEB) & (photons.passEleVeto)
                        & np.invert(photons.pixelSeed) & dRphomu & dRphoele)

        #split out the ID requirement, enabling Iso and SIEIE to be inverted for control regions
        photonID = photons.photonId >= 2

        #parse VID cuts, define loose photons (not used yet)
        photon_MinPtCut = (photons.vidCuts >> 0 & 3) >= 2
        photon_PhoSCEtaMultiRangeCut = (photons.vidCuts >> 2 & 3) >= 2
        photon_PhoSingleTowerHadOverEmCut = (photons.vidCuts >> 4 & 3) >= 2
        photon_PhoFull5x5SigmaIEtaIEtaCut = (photons.vidCuts >> 6 & 3) >= 2
        photon_ChIsoCut = (photons.vidCuts >> 8 & 3) >= 2
        photon_NeuIsoCut = (photons.vidCuts >> 10 & 3) >= 2
        photon_PhoIsoCut = (photons.vidCuts >> 12 & 3) >= 2

        photonID_NoChIsoSIEIE = (photon_MinPtCut & photon_PhoSCEtaMultiRangeCut
                                 & photon_PhoSingleTowerHadOverEmCut
                                 & photon_PhoFull5x5SigmaIEtaIEtaCut
                                 & photon_NeuIsoCut & photon_PhoIsoCut)

        tightPhotons = photons[photonSelect & photonID]
        loosePhotons = photons[photonSelect & photonID_NoChIsoSIEIE
                               & photon_PhoFull5x5SigmaIEtaIEtaCut]
        loosePhotonsSideband = photons[photonSelect & photonID_NoChIsoSIEIE &
                                       (photons.sieie > 0.012)]

        ##medium jet ID cut
        jetIDbit = 1
        if year > 2016: jetIDbit = 2

        ##check dR jet,lepton & jet,photon
        jetMu = jets['p4'].cross(tightMuon['p4'], nested=True)
        dRjetmu = (
            (jetMu.i0.delta_r(jetMu.i1)).min() > 0.4) | (tightMuon.counts == 0)

        jetEle = jets['p4'].cross(tightElectron['p4'], nested=True)
        dRjetele = ((jetEle.i0.delta_r(jetEle.i1)).min() >
                    0.4) | (tightElectron.counts == 0)

        jetPho = jets['p4'].cross(tightPhotons['p4'], nested=True)
        dRjetpho = ((jetPho.i0.delta_r(jetPho.i1)).min() >
                    0.1) | (tightPhotons.counts == 0)

        jetSelect = ((jets.pt > 30) & (abs(jets.eta) < 2.4) &
                     ((jets.jetId >> jetIDbit & 1) == 1) & dRjetmu & dRjetele
                     & dRjetpho)

        tightJets = jets[jetSelect]

        bTagWP = 0.6321  #2016 DeepCSV working point

        btagged = tightJets.btag > bTagWP

        bJets = tightJets[btagged]

        ## Define M3, mass of 3-jet pair with highest pT
        triJet = tightJets['p4'].choose(3)

        triJetPt = (triJet.i0 + triJet.i1 + triJet.i2).pt
        triJetMass = (triJet.i0 + triJet.i1 + triJet.i2).mass
        M3 = triJetMass[triJetPt.argmax()]

        leadingMuon = tightMuon[::1]
        leadingElectron = tightElectron[::1]

        leadingPhoton = tightPhotons[:, :1]
        leadingPhotonLoose = loosePhotons[:, :1]
        leadingPhotonSideband = loosePhotonsSideband[:, :1]

        #        egammaMass = (leadingElectron['p4'] + leadingPhoton['p4']).mass
        egamma = leadingElectron['p4'].cross(leadingPhoton['p4'])
        mugamma = leadingMuon['p4'].cross(leadingPhoton['p4'])
        egammaMass = (egamma.i0 + egamma.i1).mass
        mugammaMass = (mugamma.i0 + mugamma.i1).mass

        if not isData:
            #### Photon categories, using genIdx branch
            # reco photons really generated as electrons
            idx = leadingPhoton.genIdx

            matchedPho = (genpdgid[idx] == 22).any()
            isMisIDele = (abs(genpdgid[idx]) == 11).any()

            maxParent = maxHistoryPDGID(idx.content, idx.starts, idx.stops,
                                        genpdgid.content, genpdgid.starts,
                                        genpdgid.stops, genmotherIdx.content,
                                        genmotherIdx.starts,
                                        genmotherIdx.stops)

            hadronicParent = maxParent > 25

            isGenPho = matchedPho & ~hadronicParent
            isHadPho = matchedPho & hadronicParent
            isHadFake = ~(isMisIDele | isGenPho | isHadPho) & (
                leadingPhoton.counts == 1)

            #define integer definition for the photon category axis
            phoCategory = 1 * isGenPho + 2 * isMisIDele + 3 * isHadPho + 4 * isHadFake

            isMisIDeleLoose = (leadingPhotonLoose.genFlav == 13).any()
            matchedPhoLoose = (leadingPhotonLoose.genFlav == 1).any()

            # look through parentage to find if any hadrons in genPhoton parent history
            idx = leadingPhotonLoose.genIdx

            maxParent = maxHistoryPDGID(idx.content, idx.starts, idx.stops,
                                        genpdgid.content, genpdgid.starts,
                                        genpdgid.stops, genmotherIdx.content,
                                        genmotherIdx.starts,
                                        genmotherIdx.stops)

            hadronicParent = maxParent > 25

            isGenPhoLoose = matchedPhoLoose & ~hadronicParent
            isHadPhoLoose = matchedPhoLoose & hadronicParent
            isHadFakeLoose = ~(isMisIDeleLoose | isGenPhoLoose
                               | isHadPhoLoose) & (leadingPhotonLoose.counts
                                                   == 1)

            #define integer definition for the photon category axis
            phoCategoryLoose = 1 * isGenPhoLoose + 2 * isMisIDeleLoose + 3 * isHadPhoLoose + 4 * isHadFakeLoose

            isMisIDeleSideband = (leadingPhotonSideband.genFlav == 13).any()
            matchedPhoSideband = (leadingPhotonSideband.genFlav == 1).any()

            # look through parentage to find if any hadrons in genPhoton parent history
            idx = leadingPhotonSideband.genIdx

            maxParent = maxHistoryPDGID(idx.content, idx.starts, idx.stops,
                                        genpdgid.content, genpdgid.starts,
                                        genpdgid.stops, genmotherIdx.content,
                                        genmotherIdx.starts,
                                        genmotherIdx.stops)

            hadronicParent = maxParent > 25

            isGenPhoSideband = matchedPhoSideband & ~hadronicParent
            isHadPhoSideband = matchedPhoSideband & hadronicParent
            isHadFakeSideband = ~(isMisIDeleSideband | isGenPhoSideband
                                  | isHadPhoSideband) & (
                                      leadingPhotonSideband.counts == 1)

            #define integer definition for the photon category axis
            phoCategorySideband = 1 * isGenPhoSideband + 2 * isMisIDeleSideband + 3 * isHadPhoSideband + 4 * isHadFakeSideband
        else:
            phoCategory = np.ones_like(df['event'])
            phoCategoryLoose = np.ones_like(df['event'])
            phoCategorySideband = np.ones_like(df['event'])

        ### remove filter selection
        ###    This is already applied in the skim, and is causing data to fail for some reason (the flag branches are duplicated in NanoAOD for data, is it causing problems???)
#         mu_noLoose = (muTrigger & filters & passOverlapRemoval &
#                       oneMuon & eleVeto &
#                       looseMuonSel & looseElectronSel)
#         ele_noLoose = (eleTrigger & filters & passOverlapRemoval &
#                        oneEle & muVeto &
#                        looseMuonSel & looseElectronSel)

        mu_noLoose = (muTrigger & passOverlapRemoval & oneMuon & eleVeto
                      & looseMuonSel & looseElectronSel)
        ele_noLoose = (eleTrigger & passOverlapRemoval & oneEle & muVeto
                       & looseMuonSel & looseElectronSel)

        lep_noLoose = mu_noLoose | ele_noLoose

        lep_jetSel = (lep_noLoose & (tightJets.counts >= 4) &
                      (bJets.counts >= 1))
        lep_zeropho = (lep_jetSel & (tightPhotons.counts == 0))
        lep_phosel = (lep_jetSel & (tightPhotons.counts == 1))
        lep_phoselLoose = (lep_jetSel & (loosePhotons.counts == 1))
        lep_phoselSideband = (lep_jetSel & (loosePhotonsSideband.counts == 1))

        lep_phosel_3j0t = (lep_noLoose & (tightJets.counts >= 3) &
                           (bJets.counts == 0) & (tightPhotons.counts == 1))

        lepFlavor = -0.5 * ele_noLoose + 0.5 * mu_noLoose

        evtWeight = np.ones_like(df['event'], dtype=np.float64)
        if not 'Data' in dataset:
            nMCevents = self.mcEventYields[datasetFull]
            xsec = crossSections[dataset]

            evtWeight *= xsec * lumis[year] / nMCevents

            #btag key name
            #name / working Point / type / systematic / jetType
            #  ... / 0-loose 1-medium 2-tight / comb,mujets,iterativefit / central,up,down / 0-b 1-c 2-udcsg

            bJetSF_b = self.evaluator['btag%iDeepCSV_1_comb_central_0' % year](
                tightJets[tightJets.hadFlav == 5].eta,
                tightJets[tightJets.hadFlav == 5].pt,
                tightJets[tightJets.hadFlav == 5].btag)
            bJetSF_c = self.evaluator['btag%iDeepCSV_1_comb_central_1' % year](
                tightJets[tightJets.hadFlav == 4].eta,
                tightJets[tightJets.hadFlav == 4].pt,
                tightJets[tightJets.hadFlav == 4].btag)
            bJetSF_udcsg = self.evaluator[
                'btag%iDeepCSV_1_incl_central_2' %
                year](tightJets[tightJets.hadFlav == 0].eta,
                      tightJets[tightJets.hadFlav == 0].pt,
                      tightJets[tightJets.hadFlav == 0].btag)

            bJetSF = JaggedArray(content=np.ones_like(tightJets.pt.content,
                                                      dtype=np.float64),
                                 starts=tightJets.starts,
                                 stops=tightJets.stops)
            bJetSF.content[(tightJets.hadFlav == 5).content] = bJetSF_b.content
            bJetSF.content[(tightJets.hadFlav == 4).content] = bJetSF_c.content
            bJetSF.content[(
                tightJets.hadFlav == 0).content] = bJetSF_udcsg.content

            ## mc efficiency lookup, data efficiency is eff* scale factor
            btagEfficiencies = taggingEffLookup(datasetFull, tightJets.hadFlav,
                                                tightJets.pt, tightJets.eta)
            btagEfficienciesData = btagEfficiencies * bJetSF

            ##probability is the product of all efficiencies of tagged jets, times product of 1-eff for all untagged jets
            ## https://twiki.cern.ch/twiki/bin/view/CMS/BTagSFMethods#1a_Event_reweighting_using_scale
            pMC = btagEfficiencies[btagged].prod() * (
                1. - btagEfficiencies[np.invert(btagged)]).prod()
            pData = btagEfficienciesData[btagged].prod() * (
                1. - btagEfficienciesData[np.invert(btagged)]).prod()
            btagWeight = pData / pMC
            btagWeight[pData == 0] = 0

            evtWeight *= btagWeight

            eleID = self.ele_id_sf(tightElectron.eta, tightElectron.pt)
            eleIDerr = self.ele_id_err(tightElectron.eta, tightElectron.pt)
            eleRECO = self.ele_reco_sf(tightElectron.eta, tightElectron.pt)
            eleRECOerr = self.ele_reco_err(tightElectron.eta, tightElectron.pt)

            eleSF = (eleID * eleRECO).prod()
            eleSFup = ((eleID + eleIDerr) * (eleRECO + eleRECOerr)).prod()
            eleSFdo = ((eleID - eleIDerr) * (eleRECO - eleRECOerr)).prod()

            evtWeight *= eleSF

            muID = self.mu_id_sf(tightMuon.eta, tightMuon.pt)
            muIDerr = self.mu_id_err(tightMuon.eta, tightMuon.pt)
            muIso = self.mu_iso_sf(tightMuon.eta, tightMuon.pt)
            muIsoerr = self.mu_iso_err(tightMuon.eta, tightMuon.pt)
            muTrig = self.mu_iso_sf(abs(tightMuon.eta), tightMuon.pt)
            muTrigerr = self.mu_iso_err(abs(tightMuon.eta), tightMuon.pt)

            muSF = (muID * muIso * muTrig).prod()
            muSF_up = ((muID + muIDerr) * (muIso + muIsoerr) *
                       (muTrig + muTrigerr)).prod()
            muSF_down = ((muID - muIDerr) * (muIso - muIsoerr) *
                         (muTrig - muTrigerr)).prod()

            evtWeight *= muSF

        output['photon_pt'].fill(
            dataset=dataset,
            pt=tightPhotons.p4.pt[:, :1][lep_phosel].flatten(),
            category=phoCategory[lep_phosel].flatten(),
            lepFlavor=lepFlavor[lep_phosel],
            weight=evtWeight[lep_phosel].flatten())

        output['photon_eta'].fill(
            dataset=dataset,
            eta=tightPhotons.eta[:, :1][lep_phosel].flatten(),
            category=phoCategory[lep_phosel].flatten(),
            lepFlavor=lepFlavor[lep_phosel],
            weight=evtWeight[lep_phosel].flatten())

        output['photon_chIsoSideband'].fill(
            dataset=dataset,
            chIso=loosePhotonsSideband.chIso[:, :1]
            [lep_phoselSideband].flatten(),
            category=phoCategorySideband[lep_phoselSideband].flatten(),
            lepFlavor=lepFlavor[lep_phoselSideband],
            weight=evtWeight[lep_phoselSideband].flatten())

        output['photon_chIso'].fill(
            dataset=dataset,
            chIso=loosePhotons.chIso[:, :1][lep_phoselLoose].flatten(),
            category=phoCategoryLoose[lep_phoselLoose].flatten(),
            lepFlavor=lepFlavor[lep_phoselLoose],
            weight=evtWeight[lep_phoselLoose].flatten())

        output['photon_lepton_mass'].fill(
            dataset=dataset,
            mass=egammaMass[lep_phosel & ele_noLoose].flatten(),
            category=phoCategory[lep_phosel & ele_noLoose].flatten(),
            lepFlavor=lepFlavor[lep_phosel & ele_noLoose],
            weight=evtWeight[lep_phosel & ele_noLoose].flatten())
        output['photon_lepton_mass'].fill(
            dataset=dataset,
            mass=mugammaMass[lep_phosel & mu_noLoose].flatten(),
            category=phoCategory[lep_phosel & mu_noLoose].flatten(),
            lepFlavor=lepFlavor[lep_phosel & mu_noLoose],
            weight=evtWeight[lep_phosel & mu_noLoose].flatten())

        output['photon_lepton_mass_3j0t'].fill(
            dataset=dataset,
            mass=egammaMass[lep_phosel_3j0t & ele_noLoose].flatten(),
            category=phoCategory[lep_phosel_3j0t & ele_noLoose].flatten(),
            lepFlavor=lepFlavor[lep_phosel_3j0t & ele_noLoose],
            weight=evtWeight[lep_phosel_3j0t & ele_noLoose].flatten())
        output['photon_lepton_mass_3j0t'].fill(
            dataset=dataset,
            mass=mugammaMass[lep_phosel_3j0t & mu_noLoose].flatten(),
            category=phoCategory[lep_phosel_3j0t & mu_noLoose].flatten(),
            lepFlavor=lepFlavor[lep_phosel_3j0t & mu_noLoose],
            weight=evtWeight[lep_phosel_3j0t & mu_noLoose].flatten())

        output['M3'].fill(dataset=dataset,
                          M3=M3[lep_phosel].flatten(),
                          category=phoCategoryLoose[lep_phosel].flatten(),
                          lepFlavor=lepFlavor[lep_phosel],
                          weight=evtWeight[lep_phosel].flatten())

        output['M3Presel'].fill(dataset=dataset,
                                M3=M3[lep_zeropho].flatten(),
                                lepFlavor=lepFlavor[lep_zeropho],
                                weight=evtWeight[lep_zeropho].flatten())

        output['EventCount'] = len(df['event'])

        return output
Exemplo n.º 2
0
def jagged_1():
    boundaries = [0, 3, 5, 6, 9, 12, 12]
    return JaggedArray(
        boundaries[:-1], boundaries[1:],
        [0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.0, 11.0])