Пример #1
0
 def construct_global_ctx(self):
     """Constructs the global context"""
     super().construct_global_ctx()
     gtx = self.gtx
     rc = self.rc
     if "groups" in self.needed_dbs:
         rc.pi_id = get_pi_id(rc)
     rc.coll = f"{TARGET_COLL}"
     try:
         if not rc.database:
             rc.database = rc.databases[0]["name"]
     except:
         pass
     colls = [
         sorted(all_docs_from_collection(rc.client, collname), key=_id_key)
         for collname in self.needed_dbs
     ]
     for db, coll in zip(self.needed_dbs, colls):
         gtx[db] = coll
     gtx["grants"] = merge_collections_superior(gtx["proposals"],
                                                gtx["grants"],
                                                "proposal_id")
     gtx["all_docs_from_collection"] = all_docs_from_collection
     gtx["float"] = float
     gtx["str"] = str
     gtx["zip"] = zip
Пример #2
0
    def latex(self):
        """Render latex template"""
        rc = self.rc
        if rc.people:
            people = [
                fuzzy_retrieval(self.gtx["people"], ["aka", "_id", "name"],
                                rc.people[0])
            ]
        else:
            people = self.gtx["people"]

        for p in people:
            names = frozenset(p.get("aka", []) + [p["name"]])
            pubs = filter_publications(
                all_docs_from_collection(rc.client, "citations"),
                names,
                reverse=True,
            )
            bibfile = make_bibtex_file(pubs,
                                       pid=p["_id"],
                                       person_dir=self.bldir)
            emp = p.get("employment", [])
            emp = [em for em in emp if not em.get("not_in_cv", False)]
            for e in emp:
                e['position'] = e.get('position_full',
                                      e.get('position').title())
            emp.sort(key=ene_date_key, reverse=True)
            edu = p.get("education", [])
            edu.sort(key=ene_date_key, reverse=True)
            projs = filter_projects(
                all_docs_from_collection(rc.client, "projects"), names)
            grants = list(all_docs_from_collection(rc.client, "grants"))
            proposals = list(all_docs_from_collection(rc.client, "proposals"))
            grants = merge_collections_superior(proposals, grants,
                                                "proposal_id")
            pi_grants, pi_amount, _ = filter_grants(grants, names, pi=True)
            coi_grants, coi_amount, coi_sub_amount = filter_grants(grants,
                                                                   names,
                                                                   pi=False)
            aghs = awards_grants_honors(p, "honors")
            self.render(
                "resume.tex",
                p["_id"] + ".tex",
                p=p,
                title=p.get("name", ""),
                aghs=aghs,
                pubs=pubs,
                names=names,
                bibfile=bibfile,
                education=edu,
                employment=emp,
                projects=projs,
                pi_grants=pi_grants,
                pi_amount=pi_amount,
                coi_grants=coi_grants,
                coi_amount=coi_amount,
                coi_sub_amount=coi_sub_amount,
            )
            self.pdf(p["_id"])
Пример #3
0
    def sout(self):
        rc = self.rc
        since, before = None, None
        if rc.date:
            ondate = date(*[int(num) for num in rc.date.split('-')])
        else:
            ondate = date.today()

        if rc.semester:
            for v in SEMESTER_START_MONTH.values():
                if v[0] <= ondate.month <= v[1]:
                    since = date(ondate.year, v[0], 1)
                    last_day = calendar.monthrange(ondate.year, v[1])[0]
                    before = date(ondate.year, v[1], last_day)

        people = self.gtx['people']
        jg = self.gtx['grants']
        proposals = self.gtx["proposals"]
        grants = merge_collections_superior(proposals, jg, "proposal_id")
        _future_grant["begin_date"] = ondate
        _future_grant["end_date"] = ondate + timedelta(days=2190)
        _future_grant["budget"][0]["begin_date"] = ondate
        _future_grant["budget"][0]["end_date"] = ondate + timedelta(days=2190)
        grants.append(_future_grant)
        for person in people:
            p_appt = person.get('appointments', None)
            if p_appt:
                for _id, appt in p_appt.items():
                    grantid = appt.get('grant')
                    if not grantid:
                        print("No grant found in {} appt {}".format(
                            person.get('_id'), k))
                    grant = fuzzy_retrieval(grants, ["name", "_id", "alias"],
                                            grantid)
                    if not grant:
                        print("No grant found for {}".format(grantid))
                    try:
                        accountnr = grant.get('account', grant['alias'])
                    except:
                        accountnr = ''
                    loading = appt.get('loading')
                    appt_dates = get_dates(appt)
                    bd = appt_dates.get('begin_date')
                    ed = appt_dates.get('end_date')
                    if since and before:
                        if (ed >= since) and (bd <= before):
                            print(person.get('_id'), grantid, accountnr,
                                  loading, bd.strftime("%Y-%m-%d"),
                                  ed.strftime("%Y-%m-%d"))
                    else:
                        if bd <= ondate <= ed:
                            print(person.get('_id'), grantid, accountnr,
                                  loading, bd.strftime("%Y-%m-%d"),
                                  ed.strftime("%Y-%m-%d"))
Пример #4
0
    def latex(self):
        """Render latex template"""
        rc = self.rc
        if not rc.people:
            raise RuntimeError("ERROR: please rerun specifying --people name")
        if not rc.from_date:
            raise RuntimeError("ERROR: please rerun specifying --from")
        build_target = get_id_from_name(
            all_docs_from_collection(rc.client, "people"), rc.people[0])
        begin_year = int(rc.from_date.split("-")[0])
        begin_period = date_parser.parse(rc.from_date).date()
        pre_begin_period = begin_period - relativedelta(years=1)
        if rc.to_date:
            to_date = date_parser.parse(rc.to_date).date()
            end_period = to_date
            post_end_period = to_date + relativedelta(years=1)
        else:
            end_period = begin_period + relativedelta(years=1) - relativedelta(
                days=1)
            post_end_period = begin_period + relativedelta(
                years=2) - relativedelta(days=1)

        me = [p for p in self.gtx["people"] if p["_id"] == build_target][0]
        me["begin_period"] = dt.date.strftime(begin_period, "%m/%d/%Y")
        me["begin_period"] = dt.date.strftime(begin_period, "%m/%d/%Y")
        me["pre_begin_period"] = dt.date.strftime(pre_begin_period, "%m/%d/%Y")
        me["end_period"] = dt.date.strftime(end_period, "%m/%d/%Y")
        me["post_end_period"] = dt.date.strftime(post_end_period, "%m/%d/%Y")
        projs = filter_projects(self.gtx["projects"],
                                set([build_target]),
                                group="bg")
        #########
        # highlights
        #########
        for proj in projs:
            if proj.get('highlights'):
                proj["current_highlights"] = False
                for highlight in proj.get('highlights'):
                    highlight_date = dt.date(
                        highlight.get("year"),
                        month_to_int(highlight.get("month", 1)), 1)
                    if highlight_date > begin_period and highlight_date < end_period:
                        highlight["is_current"] = True
                        proj["current_highlights"] = True

        #########
        # current and pending
        #########
        pi = fuzzy_retrieval(self.gtx["people"], ["aka", "name", "_id"],
                             build_target)
        #        pi['initials'] = "SJLB"

        grants = merge_collections_superior(self.gtx["proposals"],
                                            self.gtx["grants"], "proposal_id")
        for g in grants:
            for person in g["team"]:
                rperson = fuzzy_retrieval(self.gtx["people"], ["aka", "name"],
                                          person["name"])
                if rperson:
                    person["name"] = rperson["name"]
            if g.get('budget'):
                amounts = [i.get('amount') for i in g.get('budget')]
                g['subaward_amount'] = sum(amounts)

        current_grants = [dict(g) for g in grants if is_current(g)]

        current_grants, _, _ = filter_grants(current_grants, {pi["name"]},
                                             pi=False,
                                             multi_pi=True)

        pending_grants = [
            g for g in self.gtx["proposals"] if g["status"] == "pending"
        ]
        for g in pending_grants:
            for person in g["team"]:
                rperson = fuzzy_retrieval(self.gtx["people"], ["aka", "name"],
                                          person["name"])
                if rperson:
                    person["name"] = rperson["name"]
        pending_grants, _, _ = filter_grants(pending_grants, {pi["name"]},
                                             pi=False,
                                             multi_pi=True)
        grants = pending_grants + current_grants
        for grant in grants:
            grant.update(
                award_start_date="{2}/{1}/{0}".format(
                    grant["begin_day"],
                    month_to_int(grant["begin_month"]),
                    grant["begin_year"],
                ),
                award_end_date="{2}/{1}/{0}".format(
                    grant["end_day"],
                    month_to_int(grant["end_month"]),
                    grant["end_year"],
                ),
            )
        badids = [
            i["_id"] for i in current_grants
            if not i['cpp_info'].get('cppflag', "")
        ]
        iter = copy(current_grants)
        for grant in iter:
            if grant["_id"] in badids:
                current_grants.remove(grant)
        #########
        # end current and pending
        #########

        #########
        # advising
        #########
        undergrads = filter_employment_for_advisees(self.gtx["people"],
                                                    begin_period, "undergrad")
        masters = filter_employment_for_advisees(self.gtx["people"],
                                                 begin_period, "ms")
        currents = filter_employment_for_advisees(self.gtx["people"],
                                                  begin_period, "phd")
        graduateds = filter_employment_for_advisees(
            self.gtx["people"], begin_period.replace(year=begin_year - 5),
            "phd")
        postdocs = filter_employment_for_advisees(self.gtx["people"],
                                                  begin_period, "postdoc")
        visitors = filter_employment_for_advisees(self.gtx["people"],
                                                  begin_period,
                                                  "visitor-unsupported")
        iter = deepcopy(graduateds)
        for g in iter:
            if g.get("active"):
                graduateds.remove(g)
        iter = deepcopy(currents)
        for g in iter:
            if not g.get("active"):
                currents.remove(g)

        ######################
        # service
        #####################
        mego = deepcopy(me)
        dept_service = filter_service([mego], begin_period, "department")
        mego = deepcopy(me)
        school_service = filter_service([mego], begin_period, "school")
        mego = deepcopy(me)
        uni_service = filter_service([mego], begin_period, "university")
        uni_service.extend(school_service)
        mego = deepcopy(me)
        prof_service = filter_service([mego], begin_period, "profession")
        mego = deepcopy(me)
        outreach = filter_service([mego], begin_period, "outreach")
        mego = deepcopy(me)
        lab = filter_facilities([mego], begin_period, "research")
        mego = deepcopy(me)
        shared = filter_facilities([mego], begin_period, "shared")
        mego = deepcopy(me)
        fac_other = filter_facilities([mego], begin_period, "other")
        mego = deepcopy(me)
        fac_teaching = filter_facilities([mego], begin_period, "teaching")
        mego = deepcopy(me)
        fac_wishlist = filter_facilities([mego],
                                         begin_period,
                                         "research_wish",
                                         verbose=False)
        mego = deepcopy(me)
        tch_wishlist = filter_facilities([mego], begin_period, "teaching_wish")
        mego = deepcopy(me)
        curric_dev = filter_activities([mego], begin_period, "teaching")
        mego = deepcopy(me)
        other_activities = filter_activities([mego], begin_period, "other")

        ##########################
        # Presentation list
        ##########################
        keypres = filter_presentations(self.gtx["people"],
                                       self.gtx["presentations"],
                                       self.gtx["institutions"],
                                       build_target,
                                       types=["award", "plenary", "keynote"],
                                       since=begin_period,
                                       before=end_period,
                                       statuses=["accepted"])
        invpres = filter_presentations(self.gtx["people"],
                                       self.gtx["presentations"],
                                       self.gtx["institutions"],
                                       build_target,
                                       types=["invited"],
                                       since=begin_period,
                                       before=end_period,
                                       statuses=["accepted"])
        sempres = filter_presentations(self.gtx["people"],
                                       self.gtx["presentations"],
                                       self.gtx["institutions"],
                                       build_target,
                                       types=["colloquium", "seminar"],
                                       since=begin_period,
                                       before=end_period,
                                       statuses=["accepted"])
        declpres = filter_presentations(self.gtx["people"],
                                        self.gtx["presentations"],
                                        self.gtx["institutions"],
                                        build_target,
                                        types=["all"],
                                        since=begin_period,
                                        before=end_period,
                                        statuses=["declined"])

        #########################
        # Awards
        #########################
        ahs = awards(me, since=begin_period)

        ########################
        # Publications
        ########################
        names = frozenset(me.get("aka", []) + [me["name"]])
        pubs = filter_publications(all_docs_from_collection(
            rc.client, "citations"),
                                   names,
                                   reverse=True,
                                   bold=False,
                                   since=begin_period)
        bibfile = make_bibtex_file(pubs, pid=me["_id"], person_dir=self.bldir)
        articles = [prc for prc in pubs if prc.get("entrytype") in "article"]
        nonarticletypes = [
            "book", "inbook", "proceedings", "inproceedings", "incollection",
            "unpublished", "phdthesis", "misc"
        ]
        nonarticles = [
            prc for prc in pubs if prc.get("entrytype") in nonarticletypes
        ]
        peer_rev_conf_pubs = [prc for prc in pubs if prc.get("peer_rev_conf")]
        pubiter = deepcopy(pubs)
        for prc in pubiter:
            if prc.get("peer_rev_conf"):
                peer_rev_conf_pubs = prc
                pubs.pop(prc)

        ##############
        # TODO: add Current Projects to Research summary section
        ##############

        #############
        # IP
        #############
        patents = filter_patents(self.gtx["patents"],
                                 self.gtx["people"],
                                 build_target,
                                 since=begin_period)
        licenses = filter_licenses(self.gtx["patents"],
                                   self.gtx["people"],
                                   build_target,
                                   since=begin_period)
        #############
        # hindex
        #############
        hindex = sorted(me["hindex"], key=doc_date_key).pop()

        #########################
        # render
        #########################
        self.render(
            "columbia_annual_report.tex",
            "billinge-ann-report.tex",
            pi=pi,
            p=me,
            projects=projs,
            pending=pending_grants,
            current=current_grants,
            undergrads=undergrads,
            masters=masters,
            currentphds=currents,
            graduatedphds=graduateds,
            postdocs=postdocs,
            visitors=visitors,
            dept_service=dept_service,
            uni_service=uni_service,
            prof_service=prof_service,
            outreach=outreach,
            lab=lab,
            shared=shared,
            facilities_other=fac_other,
            fac_teaching=fac_teaching,
            fac_wishlist=fac_wishlist,
            tch_wishlist=tch_wishlist,
            curric_dev=curric_dev,
            other_activities=other_activities,
            keypres=keypres,
            invpres=invpres,
            sempres=sempres,
            declpres=declpres,
            sentencecase=sentencecase,
            monthstyle=month_fullnames,
            ahs=ahs,
            pubs=articles,
            nonarticles=nonarticles,
            peer_rev_conf_pubs=peer_rev_conf_pubs,
            bibfile=bibfile,
            patents=patents,
            licenses=licenses,
            hindex=hindex,
        )
        self.pdf("billinge-ann-report")
Пример #5
0
    def latex(self):
        """Render latex template"""
        rc = self.rc
        for p in self.gtx["people"]:
            # so we don't modify the dbs when de-referencing
            names = frozenset(p.get("aka", []) + [p["name"]] + [p["_id"]])
            begin_period = date(1650, 1, 1)

            pubs = filter_publications(
                all_docs_from_collection(rc.client, "citations"),
                names,
                reverse=True,
            )
            bibfile = make_bibtex_file(pubs,
                                       pid=p["_id"],
                                       person_dir=self.bldir)
            emp = p.get("employment", [])

            for e in emp:
                e['position'] = e.get('position_full',
                                      e.get('position').title())
            emp.sort(key=ene_date_key, reverse=True)
            edu = p.get("education", [])
            edu.sort(key=ene_date_key, reverse=True)
            teach = p.get("teaching", [])
            for t in teach:
                t['position'] = t.get('position').title()

            projs = filter_projects(
                all_docs_from_collection(rc.client, "projects"), names)
            just_grants = list(all_docs_from_collection(rc.client, "grants"))
            just_proposals = list(
                all_docs_from_collection(rc.client, "proposals"))
            grants = merge_collections_superior(just_proposals, just_grants,
                                                "proposal_id")
            presentations = filter_presentations(self.gtx["people"],
                                                 self.gtx["presentations"],
                                                 self.gtx["institutions"],
                                                 p.get("_id"),
                                                 statuses=["accepted"])

            for grant in grants:
                for member in grant.get("team"):
                    dereference_institution(member, self.gtx["institutions"])
            pi_grants, pi_amount, _ = filter_grants(grants, names, pi=True)
            coi_grants, coi_amount, coi_sub_amount = filter_grants(grants,
                                                                   names,
                                                                   pi=False)
            aghs = awards_grants_honors(p, "honors")
            service = awards_grants_honors(p, "service", funding=False)
            # TODO: pull this out so we can use it everywhere
            for ee in [emp, edu]:
                for e in ee:
                    dereference_institution(e, self.gtx["institutions"])

            undergrads = filter_employment_for_advisees(
                self.gtx["people"], begin_period, "undergrad")
            masters = filter_employment_for_advisees(self.gtx["people"],
                                                     begin_period, "ms")
            currents = filter_employment_for_advisees(self.gtx["people"],
                                                      begin_period, "phd")
            graduateds = filter_employment_for_advisees(
                self.gtx["people"], begin_period, "phd")
            postdocs = filter_employment_for_advisees(self.gtx["people"],
                                                      begin_period, "postdoc")
            visitors = filter_employment_for_advisees(self.gtx["people"],
                                                      begin_period,
                                                      "visitor-unsupported")
            iter = deepcopy(graduateds)
            for g in iter:
                if g.get("active"):
                    graduateds.remove(g)
            iter = deepcopy(currents)
            for g in iter:
                if not g.get("active"):
                    currents.remove(g)

            self.render(
                "cv.tex",
                p["_id"] + ".tex",
                p=p,
                title=p.get("name", ""),
                aghs=aghs,
                service=service,
                undergrads=undergrads,
                masters=masters,
                currentphds=currents,
                graduatedphds=graduateds,
                postdocs=postdocs,
                visitors=visitors,
                pubs=pubs,
                names=names,
                bibfile=bibfile,
                education=edu,
                employment=emp,
                presentations=presentations,
                sentencecase=sentencecase,
                monthstyle=month_fullnames,
                projects=projs,
                pi_grants=pi_grants,
                pi_amount=pi_amount,
                coi_grants=coi_grants,
                coi_amount=coi_amount,
                coi_sub_amount=coi_sub_amount,
            )
            self.pdf(p["_id"])
Пример #6
0
    def db_updater(self):
        rc = self.rc
        print(
            f"Instructions/Notes:\n"
            f"  Quarters are: Q1 July thru Sept, Q2 Oct - Dec, Q3 Jan - Mar, Q4 Apr - Jun\n"
            f"  Grad salaries are about ${MONTH_COST} per month")
        grant_id = rc.grant

        begin_date, end_date = None, None
        print("Collecting Appointments for grant {}:".format(grant_id))
        expenses = self.gtx['expenses']
        people = self.gtx['people']
        jg = self.gtx['grants']
        proposals = self.gtx["proposals"]
        grants = merge_collections_superior(proposals, jg, "proposal_id")
        grant = fuzzy_retrieval(grants, ["name", "_id", "alias"], grant_id)
        if not grant:
            raise ValueError(f"ERROR: grant {grant_id} not found in grants")
        if rc.begin_date:
            begin_date = date_parser.parse(rc.begin_date).date()
        if rc.end_date:
            end_date = date_parser.parse(rc.end_date).date()
        if not begin_date:
            begin_date = get_dates(grant)['begin_date']
        if not end_date:
            end_date = get_dates(grant)['end_date']
        plot_date_list = daterange(begin_date, end_date)

        months = (end_date - begin_date).days / 30.42

        appts, begin, end = [], datetime(3070, 1,
                                         1).date(), datetime(1970, 1,
                                                             1).date()
        for person in people:
            person_appts = person.get('appointments', None)
            if person_appts:
                for _id, p_appt in person_appts.items():
                    grantid = p_appt.get('grant')
                    if grantid == grant_id:
                        loading = p_appt.get('loading')
                        bd = get_dates(p_appt).get("begin_date")
                        begin = min(begin, bd)
                        ed = get_dates(p_appt).get("end_date")
                        end = max(end, ed)
                        months_on_grant = (ed - bd).days / 30.4 * loading
                        appt = (person['_id'], bd, ed, loading,
                                months_on_grant)
                        appts.append(appt)
        appts.sort(key=lambda x: (x[0], x[1]))
        folks = []
        for app in appts:
            if app[1] < end_date:
                if app[2] >= begin_date:
                    print("{0}, from {1} to {2}, loading {3}. Total months: "
                          "{4:6.2f}".format(app[0],
                                            app[1].strftime("%Y-%m-%d"),
                                            app[2].strftime("%Y-%m-%d"),
                                            app[3], app[4]))
            folks.append(app[0])
        folks = list(set(folks))
        plots = []
        people_loadings = []
        loadingc = np.zeros(len(plot_date_list))
        for folk in folks:
            fig, ax = plt.subplots()
            loadinga = np.zeros(len(plot_date_list))
            for app in appts:
                if app[0] == folk:
                    loadingl = []
                    for day in plot_date_list:
                        if app[1] <= day <= app[2]:
                            loadingl.append(app[3])
                        else:
                            loadingl.append(0)
                    loadinga = loadinga + np.array(loadingl)
            loadingc = loadingc + loadinga

            months, loadingm, accum, days = [plot_date_list[0]], [], 0, 0
            for day, load in zip(plot_date_list, loadinga):
                if day.day == 1 and days != 0:
                    months.append(day)
                    loadingm.append(accum * MONTH_COST / days)
                    accum, days = 0, 0
                accum = accum + load
                days += 1
            months.pop()

            people_loadings.append((folk, loadinga, loadingm))
            if not rc.no_plot:
                ax.plot_date(plot_date_list,
                             loadinga,
                             ls='-',
                             marker="",
                             label=folk)
                ax.set_xlabel('date')
                ax.set_ylabel(f"loading for student {app[0]}")
                ax.legend(loc='best')
                fig.autofmt_xdate()
                plots.append(fig)

        if not rc.no_plot:
            fig, ax = plt.subplots()
            ax.plot_date(plot_date_list, loadingc, ls='-', marker="")

        print(f"\n-----------\nLoadings by month\n------------")
        index = 0
        for month in months:
            print(f"{month.isoformat()}:")
            for person in people_loadings:
                if person[2][index] > 0:
                    print(
                        f"    {person[0]}\tloading: {round(person[2][index], 2)}"
                    )
            index += 1

        print(f"\n----------------\nExpenses\n----------------")
        expenses_on_grant = [
            expense for expense in expenses
            if grant_id in expense.get('grants')
        ]

        if len(expenses_on_grant) > 1:
            expenses_on_grant.sort(key=lambda x: get_dates(x).get('end_date'))
        for expense in expenses_on_grant:
            # print(expense.get('overall_purpose'))
            for reimb in expense.get('reimbursements'):
                if reimb.get('amount') == 0:
                    amt = 0
                    for exp_item in expense.get('itemized_expenses', []):
                        amt += exp_item.get('unsegregated_expense')
                        amt += exp_item.get('prepaid_expense', 0)
                    reimb['amount'] = amt

        total_spend, month_spend, all_reimb_dates, all_reimb_amts = 0, 0, [], []
        for e in expenses_on_grant:
            reimb_amts = [
                round(i.get('amount'), 2)
                for i in e.get('reimbursements', [{}])
            ]
            reimb_dates = [
                get_dates(i).get('date',
                                 get_dates(e).get('end_date'))
                for i in e.get('reimbursements', [{}])
            ]
            all_reimb_dates.extend(reimb_dates)
            all_reimb_amts.extend(reimb_amts)
            total_spend += sum(reimb_amts)

            for reim_date, amt in zip(reimb_dates, reimb_amts):
                print(
                    f"{reim_date} (reimb date), {get_dates(e).get('end_date')} (expense date): amount: "
                    f"{amt}, ")
            print(f"  payee: {e.get('payee')} "
                  f"purpose: {e.get('overall_purpose')[:60]}")
        for month in months:
            if month >= begin_date:
                month_spend = 0
                for amt, dte in zip(all_reimb_amts, all_reimb_dates):
                    if month.year == dte.year and month.month == dte.month:
                        month_spend += amt
                print(f"{month}: expenses monthly total = {month_spend}")

        print(f"Total spend = {round(total_spend, 2)}")
        for plot in plots:
            plt.show()
Пример #7
0
    def sout(self):
        rc = self.rc
        outdated, depleted, underspent, overspent = [], [], [], []
        people = list(self.gtx['people'])
        all_appts = collect_appts(people,
                                  filter_key='type',
                                  filter_value='gra')
        all_appts.extend(
            collect_appts(people, filter_key='type', filter_value='ss'))
        all_appts.extend(
            collect_appts(people, filter_key='type', filter_value='pd'))
        if rc.projection_from_date:
            projection_from_date = date_parser.parse(
                rc.projection_from_date).date()
        else:
            projection_from_date = date.today()

        # collecting amounts and time interval for all grants
        _future_grant["begin_date"] = projection_from_date
        _future_grant["end_date"] = projection_from_date + timedelta(days=2190)
        _future_grant["budget"][0]["begin_date"] = projection_from_date
        _future_grant["budget"][0][
            "end_date"] = projection_from_date + timedelta(days=2190)
        _future_grant["burn"] = grant_burn(_future_grant, all_appts)
        all_grants = merge_collections_superior(self.gtx["proposals"],
                                                self.gtx["grants"],
                                                "proposal_id")
        all_grants.append(_future_grant)
        most_grants_id = [
            grant for grant in all_grants if grant.get('_id') not in BLACKLIST
        ]
        most_grants = [
            grant for grant in most_grants_id
            if grant.get('alias') not in BLACKLIST
        ]
        collecting_grants_with_appts = []
        for person in self.gtx['people']:
            appts = collect_appts([person],
                                  filter_key='type',
                                  filter_value='gra')
            appts.extend(
                collect_appts([person], filter_key='type', filter_value='ss'))
            appts.extend(
                collect_appts([person], filter_key='type', filter_value='pd'))
            if len(appts) > 0:
                person.update({"appts": appts})
                collecting_grants_with_appts.extend(
                    [appt.get("grant") for appt in appts])
        grants_with_appts = list(set(collecting_grants_with_appts))
        appointed_grants = [
            grant for grant in most_grants
            if grant.get("_id") in grants_with_appts
            or grant.get("alias") in grants_with_appts
        ]
        grants_end, grants_begin = None, None
        for grant in appointed_grants:
            grant['burn'] = grant_burn(grant, all_appts)
            grant_begin = get_dates(grant)['begin_date']
            grant_end = get_dates(grant)['end_date']
            grant.update({"begin_date": grant_begin, "end_date": grant_end})
            if not grants_begin or grant_begin < grants_begin:
                grants_begin = grant_begin
            if not grants_end or grant_end > grants_end:
                grants_end = grant_end

        # checking appointments
        cum_months_to_cover = 0
        for person in self.gtx['people']:
            if not person.get("appts"):
                continue
            appts = person.get("appts")
            person_dates = group_member_employment_start_end(person, "bg")
            last_emp, months_to_cover = 0, 0
            emps = [
                person_date for person_date in person_dates
                if not person_date.get("permanent")
            ]
            emps.sort(key=lambda x: x.get('end_date', 0))
            is_fully_appointed(
                person, min(get_dates(appt)['begin_date'] for appt in appts),
                max(get_dates(appt)['end_date'] for appt in appts))
            for appt in appts:
                if appt.get("grant") in BLACKLIST:
                    continue
                this_grant = fuzzy_retrieval(appointed_grants,
                                             ["_id", "alias"],
                                             appt.get('grant'))
                if not this_grant:
                    raise RuntimeError(
                        "    grant: {}, person: {}, appointment: {}, grant not found in grants database"
                        .format(appt.get("grant"), person.get("_id"),
                                appt.get("_id")))
                appt_begin, appt_end = get_dates(
                    appt)['begin_date'], get_dates(appt)['end_date']
                outdated_period, depleted_period = False, False
                for x in range((appt_end - appt_begin).days + 1):
                    day = appt_begin + relativedelta(days=x)
                    if not outdated_period:
                        if not this_grant.get('burn'):
                            print(this_grant.get('_id'))
                        if not this_grant['burn'].get(day):
                            outdated_period = True
                            outdated.append(
                                "    person: {}, appointment: {}, grant: {},\n"
                                "            from {} until {}".format(
                                    person.get('_id'), appt.get('_id'),
                                    appt.get('grant'),
                                    str(day) if day < this_grant['begin_date']
                                    else this_grant['end_date'] +
                                    relativedelta(days=1),
                                    str(min(appt_end,
                                            this_grant['begin_date']))
                                    if day < this_grant['begin_date'] else
                                    str(day)))
                    else:
                        if this_grant['burn'].get(day):
                            outdated_period = False
                    if not (depleted_period or outdated_period):
                        day_burn, this_burn = 0, this_grant['burn']
                        if appt.get('type') == 'gra':
                            day_burn = this_burn[day]['student_days']
                        elif appt.get('type') == 'pd':
                            day_burn = this_burn[day]['postdoc_days']
                        elif appt.get('type') == 'ss':
                            day_burn = this_burn[day]['ss_days']
                        if day_burn < -5:
                            # FIXME change to display depleted until next >-5 amt instead of appt_end
                            depleted.append(
                                "    person: {}, appointment: {}, grant: {},\n"
                                "            from {} until {}".format(
                                    person['_id'], appt['_id'],
                                    appt.get('grant'), str(day),
                                    str(appt_end)))
                            depleted_period = True

        # setup for plotting grants
        datearray, cum_student, cum_pd, cum_ss = [], None, None, None
        if not rc.no_plot:
            for x in range((grants_end - grants_begin).days + 1):
                datearray.append(grants_begin + relativedelta(days=x))
            cum_student, cum_pd, cum_ss = [0.0] * len(datearray), [
                0.0
            ] * len(datearray), [0.0] * len(datearray)
        plots = []

        # calculating grant surplus and deficit
        cum_underspend = 0
        for grant in appointed_grants:
            tracking = [
                balance for balance in grant.get('tracking', []) if balance
            ]
            # if all_grants[grant]:
            #     tracking = [balance for balance in all_grants[grant].get('tracking',[]) if balance]
            # else:
            #     tracking = []
            if len(tracking) > 0:
                tracking.sort(key=lambda x: x[0])
                recent_balance = tracking[-1]
                recent_balance[1] = recent_balance[1] / MONTHLY_COST_QUANTUM
            else:
                recent_balance = [projection_from_date, 0]
            budget_begin = min(
                get_dates(period)['begin_date']
                for period in grant.get('budget'))
            budget_end = max(
                get_dates(period)['end_date']
                for period in grant.get('budget'))
            if grant['begin_date'] != budget_begin:
                raise RuntimeError(
                    f"grant {grant.get('alias')} does not have a correct budget begin date. "
                    f"grant begin: {grant['begin_date']} budget begin: {budget_begin}"
                )
            elif grant['end_date'] != budget_end:
                raise RuntimeError(
                    f"grant {grant.get('alias')} does not have a correct budget end date."
                    f" grant end: {grant['end_date']} budget end: {budget_end}"
                )
            days_to_go = (grant['end_date'] - projection_from_date).days
            this_burn = grant['burn']
            end_amount = this_burn.get(grant['end_date'])['student_days'] + \
                         this_burn.get(grant['end_date'])['ss_days'] + \
                        this_burn.get(grant['end_date'])['postdoc_days']
            if end_amount > 15.25:
                underspent.append((grant['end_date'], grant.get("alias"),
                                   round(end_amount / 30.5,
                                         2), round(end_amount / days_to_go,
                                                   2)))
                cum_underspend += end_amount
            elif end_amount < -30.5:
                overspent.append(
                    "    end: {}, grant: {}, overspend amount: {} months".
                    format(str(grant['end_date']), grant.get("alias"),
                           round(end_amount / 30.5, 2)))
            # values for individual and cumulative grant burn plots
            if not rc.no_plot:
                grant_dates = [
                    grant['begin_date'] + relativedelta(days=x)
                    for x in range((grant['end_date'] -
                                    grant['begin_date']).days + 1)
                ]
                this_student, this_pd, this_ss = [0.0] * len(grant_dates), [0.0] * len(grant_dates), \
                                                 [0.0] * len(grant_dates)
                counter = 0
                for x in range(len(datearray)):
                    day_burn = this_burn.get(datearray[x])
                    if day_burn:
                        this_student[counter] = day_burn['student_days']
                        this_pd[counter] = day_burn['postdoc_days']
                        this_ss[counter] = day_burn['ss_days']
                        cum_student[x] += day_burn['student_days']
                        cum_pd[x] += day_burn['postdoc_days']
                        cum_ss[x] += day_burn['ss_days']
                        counter += 1
                if not rc.verbose:
                    if max(grant_dates) >= projection_from_date - timedelta(
                            days=730):
                        plots.append(
                            plotter(grant_dates,
                                    student=this_student,
                                    pd=this_pd,
                                    ss=this_ss,
                                    title=grant.get("alias"))[0])
                else:
                    plots.append(
                        plotter(grant_dates,
                                student=this_student,
                                pd=this_pd,
                                ss=this_ss,
                                title=grant.get("alias"))[0])

        if outdated:
            outdated.sort(key=lambda mess: mess[-10:])
            print("appointments on outdated grants:")
            for appt in outdated:
                print(appt)
        if depleted:
            depleted.sort(key=lambda mess: mess[-10:])
            print("appointments on depleted grants:")
            for appt in depleted:
                print(appt)
        if underspent:
            underspent.sort(key=lambda x: x[0])
            print("underspent grants:")
            for grant_info in underspent:
                print(
                    f"    {grant_info[1]}: end: {grant_info[0]}\n"
                    f"      projected underspend: {grant_info[2]} months, "
                    f"balance as of {recent_balance[0]}: {recent_balance[1]}\n"
                    f"      required ss+gra burn: {grant_info[3]}")
            print(
                f"cumulative underspend = {round(cum_underspend/30.5, 2)} months, cumulative months to support = {round(cum_months_to_cover, 2)}"
            )
        if overspent:
            print("overspent grants:")
            for grant in overspent:
                print(grant)

        if not rc.no_plot:
            for plot in plots:
                if not rc.no_gui:
                    plt.show()
            cum_plot, cum_ax, outp = plotter(datearray,
                                             student=cum_student,
                                             pd=cum_pd,
                                             ss=cum_ss,
                                             title="Cumulative burn")
            if not rc.no_gui:
                plt.show()

            print(outp)

        return