compile_term_summaries.js

Examine the entire allstudents.json file, and extract a summary for each term. The following categories are summarized:

Numbers are broken down by department.subdivisons and department.plan_codes

Summary for previous and current academic year is stored in ./jekyll/_data/overview.json

Summary for each term is stored in ./jekyll/_data/term_data/<term_key>/term_summary.json


Table of Contents


/** department_summary.js

@overview generate json for use by gradphile overview pages

*/

Setup

Dependencies


var fs = require('fs');
var readYAML = require('read-yaml');
require('./logging')(__filename);

var bc = require("./bc_utilities.js");

Some Constants


const kAllAreasKey = "all";
const kAllPlansKey = "all";

Load Data for summary

reads in:

and filter down to current faculty


const allstudents = bc.readJSON("./jekyll/_data/allstudents.json");

const allfaculty = bc.initializeFromCSVPathWithKey("./jekyll/_data/dept/faculty.csv", null);

const department = bc.initializeFromYAMLPath("./jekyll/_data/dept/department.yaml");

const current_faculty = allfaculty.filter(function(f) {
           return (f.past_faculty != "yes");
        })
        
        

Set Current Academic Year Terms

We are summarizing for current term and academic year, so we need term keys and codes for current term and current academic year.

We will approximate start of terms with some generic dates, which vary a little from specific term starts:

assume fall runs from 8/1 to 12/20
assume spring runs from 12/21 to 4/30
assume summer runs from 5/1 to 7/31


let now = new Date();
let month = now.getMonth() + 1;
let date = now.getDate();
let year = now.getFullYear();

let term = "fall";
let term_num = 9;

if (month == 12 && date >=21) {
    term = "spring";
    term_num = 1;
}
if (month <= 4) {
    term = "spring";
    term_num = 1;
}
if (month >= 5 && month <= 7) {
    term = "summer";
    term_num = 6;
}
const kCurrentTermKey = year +"_" + term;
const kCurrentTermCode = year +"/" + term_num;

const kThisYear = (term == "fall") ? year : (year - 1);
const kLastYear = kThisYear - 1;

Base Summary Structure

Each summary category defines a list of subkeys. Each subkey can be a summary number (eg summary.percentFemale) or a map of subcategories (for example, summary.gender[“F”] and gender[“M”]).

The getSummaryWithAreaAndPlanKeys function sets up the summary data structure, using the map of subkeys, to subdivide into “areas” across department.subdivisions and “plans” across department.plan_codes for degrees. Both summary.areas and summary.plans have “all” keys that accumulate across all students enrolled in that term. Note that plans[“all”] could be larger than areas[“all”], because a student can have multiple contemporaneous plans, but only belong to one area.


function getSummaryWithAreaAndPlanKeys(subKeys) {

    let summary = { "areas" : {}, "plans" : {} };
    
    summary.areas[kAllAreasKey]={};
    department.subdivisions.forEach(function(area) {
            summary.areas[area.abbr] = {};
    });
    
     
    summary.plans[kAllPlansKey] = {};
    department.plan_codes.forEach(function(plan) {
         summary.plans[plan] = {};
    });
    
    for (sk in subKeys) {
        
        // console.log(sk + ": " + subKeys[sk]);
        
        if ("Number" == subKeys[sk]) {
            summary.areas[kAllAreasKey][sk] = 0;
            department.subdivisions.forEach(function(area) {
                summary.areas[area.abbr][sk] = 0;
            });
            
            summary.plans[kAllPlansKey][sk] = 0;
            department.plan_codes.forEach(function(plan) {
                 summary.plans[plan][sk] = 0;
            });
                           
        }
        else if (Array.isArray(subKeys[sk])) {
        
            summary.areas[kAllAreasKey][sk] = {}
            subKeys[sk].forEach(function(k) {
                summary.areas[kAllAreasKey][sk][k] = 0;            
            });
            department.subdivisions.forEach(function(area) {
                summary.areas[area.abbr][sk] = {};
                subKeys[sk].forEach(function(k) {
                    summary.areas[area.abbr][sk][k] = 0;            
                });
            });

            summary.plans[kAllPlansKey][sk] = {}
            subKeys[sk].forEach(function(k) {
                summary.plans[kAllPlansKey][sk][k] = 0;            
            });
            department.plan_codes.forEach(function(plan) {
                summary.plans[plan][sk] = {};
                subKeys[sk].forEach(function(k) {
                    summary.plans[plan][sk][k] = 0;            
                });
            });
                        
        }
    
    }
    
    // console.log(summary);
    
    return summary;

}

Summarizing Categories

The summarize_<category> functions have the same general structure:

  1. allocate the summary data structure with getSummaryWithAreaAndPlanKeys

  2. load any required ancillary files

  3. enumerate across the given student array

  4. accumulate numbers for the student’s area

  5. enumerate across the student’s current plans, and accumulate numbers for the student’s plan code

  6. At the end, calculate any percentages that require knowing the totals and subtotals.

Class Size Summary

Sum the total number of students who are in their first year, or second year, etc. of study up to 8 years. Any student in the program for more than 8 years is counted in the 8 years bin. Incoming students (students who will be admitted in the next 12 months) are summed in the zero-year bin.

Depends on refactor_plans.js having updated allstudents.json with derived variables


const kClassSizeSubKeys = {

    0: "Number",
    1: "Number",
    2: "Number",
    3: "Number",
    4: "Number",
    5: "Number",
    6: "Number",
    7: "Number",
    8: "Number"


};

const kMaxYear = 8;

function summarize_class_size(current_students,term_key){
    // pass in array of students enrolled in a specific term

    let class_size_summary = getSummaryWithAreaAndPlanKeys(kClassSizeSubKeys);
    
    let term_months  = termKey2Months(term_key) + 1;
    // add 1 month to catch those who have entered this term
    
    function getYear(admit_term_code) {
    
        let admit_months = termCode2Months(admit_term_code);
        
        let year = 0;
        if ((term_months - admit_months) < 0) { year = 0; } // incoming
        else {
            year =  Math.ceil((term_months - admit_months)/12);
            if (year > kMaxYear)   { year = kMaxYear; } 
        }  
        
        return year;
    
    
    }
    current_students.forEach(function(s){
            
        let year = getYear(s.admit_term);
       
        class_size_summary.areas[kAllAreasKey][year]++;
        class_size_summary.areas[s.area][year]++;  
        
        let plans = currentPlansInTerm(s,term_key);
            
        plans.forEach(function(p) {
        
            let year = getYear(s.academic_plans[p].admit_term);
        
            class_size_summary.plans[kAllPlansKey][year]++;
            class_size_summary.plans[p][year]++;  
        
        });
              
    });
    
    return class_size_summary;
    
} // summarize_class_size

Class Enrollment and Registration summary

Here we determine the number of students who are not only enrolled, but also registered in the given term, and total number of hours taken across entire area or plan. Requires


const kEnrollmentSubKeys = {

    "enrolled": "Number",
    "registered": "Number",
    "hours" : "Number"


};


function summarize_enrollment(current_students, term_key){


    let class_enrolled_summary = getSummaryWithAreaAndPlanKeys(kEnrollmentSubKeys);

    // load registration for given term
    
    let registration = {};
    
    let registration_path =  __dirname + 
                                "/jekyll/_data/term_data/" 
                                + term_key 
                                + "/registration.json";
    
    if (fs.existsSync(registration_path)){
        let registration = bc.readJSON(registration_path);
    }
    else {
        console.log(term_key + " registration missing")
    }
    
    
    current_students.forEach(function(s){

        class_enrolled_summary.areas[kAllAreasKey].enrolled++;
        class_enrolled_summary.areas[s.area].enrolled++;
        
        if (bc.notUndefinedAndNotNull(registration[s.fsuid])){
            class_enrolled_summary.areas[kAllAreasKey].registered++;   
            class_enrolled_summary.areas[kAllAreasKey].hours += registration[s.fsuid].hours; 
            class_enrolled_summary.areas[s.area].registered++; 
            class_enrolled_summary.areas[s.area].hours += registration[s.fsuid].hours;
       
        }
        
        let plans = currentPlansInTerm(s,term_key);
            
        plans.forEach(function(p) {
        
            class_enrolled_summary.plans[kAllPlansKey].enrolled++;
            class_enrolled_summary.plans[p].enrolled++;
            if (bc.notUndefinedAndNotNull(registration[s.fsuid])){
                class_enrolled_summary.plans[kAllPlansKey].registered++;    
                class_enrolled_summary.plans[kAllPlansKey].hours += registration[s.fsuid].hours;
                class_enrolled_summary.plans[p].registered++;    
                class_enrolled_summary.plans[p].hours += registration[s.fsuid].hours;
            }
        
        });
        
    });
    
    return class_enrolled_summary;
    
} // summarize_enrollment

Demographics summary

Summarize the citizenship broadly divided into US & RA, Intl, and LAC students.

Depends on refactor_plans.js having updated allstudents.json with derived variables.


const kCitizenSubKeys =  {
    "US & RA" : "Number",
    "LAC" : "Number",
    "Intl" : "Number",
    "total" : "Number",
    "percentIntlNotLAC" : "Number",
    "percentIntl" : "Number"
};    



function summarize_citizenship(current_students, term_key){
    // pass in array of students enrolled in a specific term

    let citizen_summary = getSummaryWithAreaAndPlanKeys(kCitizenSubKeys);
    
         
    current_students.forEach(function(s){
              
       citizen_summary.areas[kAllAreasKey]["total"]++;
       citizen_summary.areas[s.area]["total"]++;
       
       if (s.residency == "usa") {
            citizen_summary.areas[kAllAreasKey]["US & RA"]++;
            citizen_summary.areas[s.area]["US & RA"]++;
       }
       else {
            citizen_summary.areas[kAllAreasKey]["Intl"]++;
            citizen_summary.areas[s.area]["Intl"]++;
       }
       if (s.lac) {
            citizen_summary.areas[kAllAreasKey]["LAC"]++;
            citizen_summary.areas[s.area]["LAC"]++;
       }
       
        let plans = currentPlansInTerm(s,term_key);
            
        plans.forEach(function(p) {
            
            citizen_summary.plans[kAllPlansKey]["total"]++;
            citizen_summary.plans[p]["total"]++;

            if (s.residency == "usa") {
                citizen_summary.plans[kAllPlansKey]["US & RA"]++;
                citizen_summary.plans[p]["US & RA"]++;
            }
            else {
                citizen_summary.plans[kAllPlansKey]["Intl"]++;
                citizen_summary.plans[p]["Intl"]++;
            }
            if (s.lac) {
                citizen_summary.plans[kAllPlansKey]["LAC"]++;
                citizen_summary.plans[p]["LAC"]++;
            }

        });
                     
    });
    
    citizen_summary.areas[kAllAreasKey]["percentIntlNotLAC"] = 100 
        * (citizen_summary.areas[kAllAreasKey]["Intl"] - citizen_summary.areas[kAllAreasKey]["LAC"] ) 
        / citizen_summary.areas[kAllAreasKey]["total"] ;
 
     citizen_summary.areas[kAllAreasKey]["percentIntl"] = 100 
        * citizen_summary.areas[kAllAreasKey]["Intl"]  
        / citizen_summary.areas[kAllAreasKey]["total"] ;
           
    department.subdivisions.forEach(function(area) {
        citizen_summary.areas[area.abbr]["percentIntlNotLAC"] = 100 
            * (citizen_summary.areas[area.abbr]["Intl"] - citizen_summary.areas[area.abbr]["LAC"])
            / citizen_summary.areas[area.abbr]["total"] ;    
            
         citizen_summary.areas[area.abbr]["percentIntl"] = 100 
            * citizen_summary.areas[area.abbr]["Intl"]
            / citizen_summary.areas[area.abbr]["total"] ;  
            
    });

    citizen_summary.plans[kAllAreasKey]["percentIntlNotLAC"] = 100 
        * (citizen_summary.plans[kAllAreasKey]["Intl"] - citizen_summary.plans[kAllAreasKey]["LAC"] ) 
        / citizen_summary.plans[kAllAreasKey]["total"] ;
 
     citizen_summary.plans[kAllAreasKey]["percentIntl"] = 100 
        * citizen_summary.plans[kAllAreasKey]["Intl"]  
        / citizen_summary.plans[kAllAreasKey]["total"] ;
           
    department.plan_codes.forEach(function(plan) {
        citizen_summary.plans[plan]["percentIntlNotLAC"] = 100 
            * (citizen_summary.plans[plan]["Intl"] - citizen_summary.plans[plan]["LAC"])
            / citizen_summary.plans[plan]["total"] ;    
            
         citizen_summary.plans[plan]["percentIntl"] = 100 
            * citizen_summary.plans[plan]["Intl"]
            / citizen_summary.plans[plan]["total"] ;  
            
    });


    return citizen_summary;
    
} // citizen_summary

Gender summary

Summarize male, female, other (O), or unknown (?).


const kGenderOptions = [
    "F",
    "M",
    "O",
    "?"

];

const kGenderSubKeys = {

    "gender" : kGenderOptions ,
    "total" : "Number",
    "percentFemale" : "Number"

};



function summarize_gender(current_students,term_key){
    // pass in array of students enrolled in a specific term

    let gender_summary = getSummaryWithAreaAndPlanKeys(kGenderSubKeys);

    current_students.forEach(function(s){

            gender_summary.areas[kAllAreasKey].total++;
            gender_summary.areas[kAllAreasKey].gender[s.sex]++;
            gender_summary.areas[s.area].gender[s.sex]++;
            gender_summary.areas[s.area].total++;
            
            let plans = currentPlansInTerm(s,term_key);
            
            plans.forEach(function(p) {
            
                gender_summary.plans[kAllPlansKey].total++;
                gender_summary.plans[kAllPlansKey].gender[s.sex]++;
                gender_summary.plans[p].gender[s.sex]++;
                gender_summary.plans[p].total++;
            
            });
              
    });
    
    gender_summary.areas[kAllAreasKey].percentFemale =   100 
            *  gender_summary.areas[kAllAreasKey].gender["F"] 
            / gender_summary.areas[kAllAreasKey].total;
            
    department.subdivisions.forEach(function(area) {
         gender_summary.areas[area.abbr].percentFemale =   100 
            *  gender_summary.areas[area.abbr].gender["F"] 
            / gender_summary.areas[area.abbr].total;
        });
    
    gender_summary.plans[kAllPlansKey].percentFemale =   100 
            *  gender_summary.plans[kAllPlansKey].gender["F"] 
            / gender_summary.plans[kAllPlansKey].total;
            
     department.plan_codes.forEach(function(plan) {
         gender_summary.plans[plan].percentFemale =   100 
            *  gender_summary.plans[plan].gender["F"] 
            / gender_summary.plans[plan].total;
        });
    
    
    
    
    
    return gender_summary;
    
} // gender_summary

Ethnicity summary

Accumulate totals of FSU-defined ethnicity, which are self-declared by the student.

Relies on refactor_plans.js to have determine if underrepresented minority, defines as residency is “usa” and ethnicity = AMIND, PACIF,HISPA, BLACK, or MULTIPLE.


const kEthnicityOptions = [
    "WHITE",
    "ASIAN",
    "NOTSPEC",
    "PACIF",
    "AMIND",
    "HISPA",
    "BLACK",
    "MULTIPLE",
];

const kEthnicitySubKeys =  {

    "ethnicity" : kEthnicityOptions,
    "total" :  "Number",
    "urMinority" : "Number",
    "percentMinority" : "Number"

};

function summarize_ethnicity(current_students, term_key){
    // pass in array of students enrolled in a specific term

    let ethnicity_summary = getSummaryWithAreaAndPlanKeys(kEthnicitySubKeys);
    
    
    current_students.forEach(function(s){
        ethnicity_summary.areas[kAllAreasKey].total++;
        ethnicity_summary.areas[s.area].total++;
        ethnicity_summary.areas[kAllAreasKey].ethnicity[s.ethnicity]++;
        ethnicity_summary.areas[s.area].ethnicity[s.ethnicity]++;
        if (s.minority) {
           ethnicity_summary.areas[kAllAreasKey].urMinority++;
           ethnicity_summary.areas[s.area].urMinority++;
        }
        
       let plans = currentPlansInTerm(s,term_key);
            
       plans.forEach(function(p) {
       
            ethnicity_summary.plans[kAllPlansKey].total++;
            ethnicity_summary.plans[p].total++;
            ethnicity_summary.plans[kAllPlansKey].ethnicity[s.ethnicity]++;
            ethnicity_summary.plans[p].ethnicity[s.ethnicity]++;
            if (s.minority) {
               ethnicity_summary.plans[kAllPlansKey].urMinority++;
               ethnicity_summary.plans[p].urMinority++;
            }
              
       });
        
        
    });
    
    ethnicity_summary.areas[kAllAreasKey].percentMinority =   100 
            *  ethnicity_summary.areas[kAllAreasKey].urMinority 
            / ethnicity_summary.areas[kAllAreasKey].total;
            
     department.subdivisions.forEach(function(area) {
         ethnicity_summary.areas[area.abbr].percentMinority =   100 
            *  ethnicity_summary.areas[area.abbr].urMinority 
            / ethnicity_summary.areas[area.abbr].total;
        });
        
 
     ethnicity_summary.plans[kAllPlansKey].percentMinority =   100 
            *  ethnicity_summary.plans[kAllPlansKey].urMinority 
            / ethnicity_summary.plans[kAllPlansKey].total;
            
     department.plan_codes.forEach(function(plan) {
         ethnicity_summary.plans[plan].percentMinority =   100 
            *  ethnicity_summary.plans[plan].urMinority 
            / ethnicity_summary.plans[plan].total;
        });
       
        
        
    
    return ethnicity_summary;
    
} // ethnicity_summary

Graduation Summary

Look at plans of every student.


const  kGraduationSubKeys = { 
    "graduated": "Number", 
    "left": "Number",
    "continued": "Number", 
    "admitted" : "Number" 
};

function summarize_graduation(current_students, term_key){

    let graduation_summary = getSummaryWithAreaAndPlanKeys(kGraduationSubKeys);
    
    
   // load registration for given term
   
   let registration = {};
   
   let registration_path =  __dirname 
                            + "/jekyll/_data/term_data/" 
                            + term_key 
                            + "/registration.json"
   
   if (fs.existsSync(registration_path)) {
   
     registration = bc.readJSON(registration_path);
     
   }
   else {
        console.log(term_key + " registration missing")
    }
    
    
    
    let term_months = termKey2Months(term_key);
    current_students.forEach(function(s){


            let admit_flag = false;
            let left_flag = false;
            let outcome = "left";
            
            let plans = currentPlansInTerm(s,term_key);
            
            plans.forEach(function(p) {
           
                let plan_admit_flag = false;
                let plan_left_flag = false;
                
               plan =  s.academic_plans[p];
                
               let  admit_months =  termCode2Months(plan.admit_term);
                if (admit_months == term_months) {
                     admit_flag = true;
                     plan_admit_flag = true;
                     graduation_summary.plans[kAllPlansKey]["admitted"]++;
                     graduation_summary.plans[p]["admitted"]++;
                }
            
                 if (bc.notUndefinedAndNotNull(plan.last_term)) {
                   let plan_last_months = termCode2Months(plan.last_term);

                    if (plan_last_months == term_months) {
                        left_flag = true;
                        plan_left_flag = true;
                        if (plan.outcome == "graduated") {
                            outcome = "graduated";
                             graduation_summary.plans[kAllPlansKey]["graduated"]++;
                             graduation_summary.plans[p]["graduated"]++;
                        }
                        else {
                             graduation_summary.plans[kAllPlansKey]["left"]++;
                             graduation_summary.plans[p]["left"]++;
                        }
                    }
                }
                
                
                if (!plan_admit_flag && !plan_left_flag) {
                    graduation_summary.plans[kAllAreasKey]["continued"]++;
                    graduation_summary.plans[p]["continued"]++;
                }
                
            }); // next plan
            
            
            if (admit_flag) {
                graduation_summary.areas[kAllAreasKey]["admitted"]++;
                graduation_summary.areas[s.area]["admitted"]++;
            }

            if (left_flag){
                if (outcome == "graduated")  {
                    graduation_summary.areas[kAllAreasKey]["graduated"]++;
                    graduation_summary.areas[s.area]["graduated"]++;
                }
                else {
                    graduation_summary.areas[kAllAreasKey]["left"]++;
                    graduation_summary.areas[s.area]["left"]++;
            
                }
            }
            
            if (!admit_flag && !left_flag) {
                graduation_summary.areas[kAllAreasKey]["continued"]++;
                graduation_summary.areas[s.area]["continued"]++;
            
            }
            
    
            

    });
    
    return graduation_summary;



}

Support Summary

Run through the _data/term_data/<term_key>/assignments.csv file, and summarize:

We check length of fields, because blank fields may be zero-length strings in the csv file.


const kSupportSubKeys = {

    "TA" : "Number",
    "RA" : "Number",
    "NFR" : "Number",
    "fellowship" : "Number"
    
};


function summarize_support(current_students, term_key){
                        
    let support_summary = getSummaryWithAreaAndPlanKeys(kSupportSubKeys);

    
    
    // load assignments for given term
    
    let assignments = {};
    
    let assignments_path = __dirname + 
                                "/jekyll/_data/term_data/" 
                                + term_key 
                                + "/assignments.csv";
    
    if (fs.existsSync(assignments_path)) {
        assignments = bc.initializeFromCSVPathWithKey(assignments_path, 'fsuid');
    }
    else {
        console.log(term_key + " assignments missing")
    }
    
    current_students.forEach(function(s){

        if (typeof assignments[s.fsuid] != "undefined") {
        
            let appt = assignments[s.fsuid];
            
            let appointment_type = "NFR";
            let has_fellowship = false;
            
            if (appt.appointment.length > 0){
            
                appointment_type = appt.appointment;
                            
                if ("RA" == appt.appointment && appt.ra_type == "fellowship"){
                     has_fellowship = true;
                }
                
                support_summary.areas[kAllAreasKey][appointment_type] ++;
                support_summary.areas[appt.area][appointment_type]++;
                
                if (has_fellowship){
                    support_summary.areas[kAllAreasKey]["fellowship"]++;
                    support_summary.areas[appt.area]["fellowship"]++;
                }
  
                let plans = currentPlansInTerm(s,term_key);
            
                plans.forEach(function(p) {
                 
                    support_summary.plans[kAllPlansKey][appointment_type] ++;
                    support_summary.plans[p][appointment_type]++;
                     if (has_fellowship){
                        support_summary.plans[kAllPlansKey]["fellowship"]++;
                        support_summary.plans[p]["fellowship"]++;
                    }
                    
                });
                
            }

     }
            

    });
    
    return support_summary;

}

Term Utilities


const term_name = {

    "1" : "spring",
    "6" : "summer",
    "9" : "fall"

};


function termCode2term(code) {

    let parts = code.split("/");
    return {  "year": parts[0], "term" : parts[1] };

}

//--------------------------------------------------------------

function incrementTerm(term) {
    
    if (term.term == 1) {
        term.term = 6;
    }
    else if (term.term == 6) {
        term.term = 9;
    }
    else if (term.term == 9) {
        term.term = 1;
        term.year++;
    }

}
//--------------------------------------------------------------

function lessOrSameTerm(term1,term2) {
    // term1 falls earlier than term2, or is same term

    return ((term1.year < term2.year) || (term1.year == term2.year && term1.term <= term2.term));

}


//--------------------------------------------------------------


function termCode2Months(term_code) {

    let parts = term_code.split("/");
    return (parseInt(parts[0],10) * 12 + parseInt(parts[1],10));
}

//--------------------------------------------------------------


function termKey2Months(term_key) {
    
    let parts = term_key.split("_");
    let months = parseInt(parts[0],10) * 12;
    if ("spring" == parts[1]){
        months+=1;
    }
    if ("summer" == parts[1]){
         months+=6;
    }
    if ("fall" == parts[1]){
        months+=9;
    }
   
    return months;

}

//--------------------------------------------------------------


 function enrolledInTerm(s,term_key) {
 
    let admit_months = termCode2Months(s.admit_term);
    
    let last_months = 999999; 
    if (bc.notUndefinedAndNotNull(s.last_term)) {
        last_months =  termCode2Months(s.last_term);
    }
    let term_months = termKey2Months(term_key);
    
    
    return (admit_months <= term_months && term_months <= last_months);
    

}

//--------------------------------------------------------------

function currentPlansInTerm(s,term_key) {

        let term_months = termKey2Months(term_key);
        let plans = [];
        for (var p in s.academic_plans) {
             plan =  s.academic_plans[p];
               
               let  admit_months =  termCode2Months(plan.admit_term);

               let plan_last_months = 999999;
                
                 if (bc.notUndefinedAndNotNull(plan.last_term)) {
                    plan_last_months = termCode2Months(plan.last_term);
                }
            
            
            if (admit_months <= term_months && term_months<= plan_last_months) {
                plans.push(p);
            }
        }
        return plans;
}

//--------------------------------------------------------------


 function enrolledInTermOrFuture(s,term_key) {
 
    // if enrolled now, or will be enrolled in next two terms (less than 12 months from this term)
 
    let admit_months = termCode2Months(s.admit_term);
    
    let last_months = 999999; 
    if (bc.notUndefinedAndNotNull(s.last_term)) {
        last_months =  termCode2Months(s.last_term);
    }
    let term_months = termKey2Months(term_key);
    
    
    return (admit_months <= term_months && term_months <= last_months || (admit_months - term_months < 12));
    

}

Terms in Database

Find the earliest term in the database from the first admissions term.


let current_year = (new Date()).getFullYear();
let current_month =  (new Date()).getMonth() + 1;
let current_semester = (current_month < 6) ? 1 : ((current_month < 9) ? 6 : 9);
let current_term =  { "term": current_semester, "year" : current_year };

let this_current_term =  { "term": current_semester, "year" : current_year };
let start_term = { "term": current_semester, "year" : current_year };

allstudents.reduce(function(acc,s) {  
    
    let term = termCode2term(s.admit_term);
    
    if (term.year < acc.year) {
        acc.year = term.year; acc.term = term.term;
    }
    else if (term.year == acc.year && term.term < acc.term) {
        acc.term = term.term;
    }
    
    return acc;

},start_term);

Compile Term summaries for all terms

Compile Term summaries for all terms in the database, and save them to term_data/term_summary.


let term_summaries = {};

for (term = start_term; lessOrSameTerm(term,this_current_term); incrementTerm(term)) {

    let term_key = term.year + "_"  + term_name[term.term];
    
    let current_students = allstudents.filter(function(s) { 
            return enrolledInTerm(s,term_key);
        });
    
    let current_and_incoming_students = allstudents.filter(function(s) { 
            return enrolledInTermOrFuture(s,term_key);
        });
        
    term_summaries[term_key] = {};
    term_summaries[term_key].term = term_key;
    term_summaries[term_key].support = summarize_support(current_students,term_key);
    term_summaries[term_key].graduation = summarize_graduation(current_students,term_key);
    term_summaries[term_key].ethnicity = summarize_ethnicity(current_students,term_key);
    term_summaries[term_key].gender = summarize_gender(current_students,term_key);
    term_summaries[term_key].citizenship = summarize_citizenship(current_students,term_key);
    term_summaries[term_key].enrollment = summarize_enrollment(current_students,term_key);
    term_summaries[term_key].class_size = summarize_class_size(current_and_incoming_students,term_key);
    
    
    fs.writeFileSync(__dirname+"/jekyll/_data/term_data/" + term_key + "/term_summary.json", JSON.stringify(term_summaries[term_key], null,5));

}

Compile Academic Year Summary

Graduate Faculty Status summary

Set up a map of all faculty and areas, with counts of the 6 possible Graduate Status options. Just filter the faculty by the given area and GFS status, and return the size of the filtered array.



const kGFSOptions = [

    "none",
    "GFS",
    "coDDS",
    "coMDS",
    "RGFS",
    "GTS"
];    



function summarize_GFS() {

    let GFS_summary ={};

     GFS_summary[kAllAreasKey] = {};
     kGFSOptions.forEach(function(gfs_status){
            GFS_summary[kAllAreasKey][gfs_status] = current_faculty.filter(function(f){
                    return(f.graduate_status == gfs_status);
            }).length;    
        });

    department.subdivisions.forEach(function(area) {
        GFS_summary[area.abbr] = {};
        kGFSOptions.forEach(function(gfs_status){
            GFS_summary[area.abbr][gfs_status] = current_faculty.filter(function(f){
                    return(f.graduate_status == gfs_status && f.area == area.abbr);
            }).length;    
        });
    });
    
    return GFS_summary;
} // summarize_GFS

Compile Academic Year Term Summaries

Compile summaries for terms of this academic year and last academic year, and save to _data/overview.json.


let summary = 
    {  "last_year" : { "label": kLastYear + "-" + (kLastYear+1), 
                       "fall" : { "key": kLastYear + "_fall" }, 
                       "spring" : { "key": (kLastYear + 1) + "_spring" }, 
                       "summer" : { "key": (kLastYear + 1) + "_summer" } 
                    },
       "this_year" : { "label": kThisYear + "-" + (kThisYear+1), 
                       "fall" : { "key": kThisYear + "_fall" }, 
                       "spring" : { "key": (kThisYear + 1) + "_spring" }, 
                       "summer" : { "key": (kThisYear + 1) + "_summer" } 
                    },
                    
        "terms": {}
        
    };
    
const kTermKeys = [
    kLastYear + "_fall",
    (kLastYear + 1) + "_spring" ,
    (kLastYear + 1) + "_summer" , 
    kThisYear + "_fall" ,
    (kThisYear + 1) + "_spring",
    (kThisYear + 1)+  "_summer" 
];
    

kTermKeys.forEach(function(term_key) {

    summary.terms[term_key] = term_summaries[term_key];

});


summary.gfs_faculty = summarize_GFS();

fs.writeFileSync(__dirname+"/jekyll/_data/overview.json", JSON.stringify(summary, null,5));