156 lines
5.8 KiB
Python
156 lines
5.8 KiB
Python
##############################################################################
|
|
# ScoDoc
|
|
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
|
# See LICENSE
|
|
##############################################################################
|
|
|
|
"""Résultats semestres BUT
|
|
"""
|
|
import time
|
|
import numpy as np
|
|
import pandas as pd
|
|
|
|
from app import log
|
|
from app.comp import moy_ue, moy_sem, inscr_mod
|
|
from app.comp.res_common import NotesTableCompat
|
|
from app.comp.bonus_spo import BonusSport
|
|
from app.models import ScoDocSiteConfig
|
|
from app.models.moduleimpls import ModuleImpl
|
|
from app.models.ues import UniteEns
|
|
from app.scodoc.sco_codes_parcours import UE_SPORT
|
|
|
|
|
|
class ResultatsSemestreBUT(NotesTableCompat):
|
|
"""Résultats BUT: organisation des calculs"""
|
|
|
|
_cached_attrs = NotesTableCompat._cached_attrs + (
|
|
"modimpl_coefs_df",
|
|
"modimpls_evals_poids",
|
|
"sem_cube",
|
|
)
|
|
|
|
def __init__(self, formsemestre):
|
|
super().__init__(formsemestre)
|
|
|
|
if not self.load_cached():
|
|
t0 = time.time()
|
|
self.compute()
|
|
t1 = time.time()
|
|
self.store()
|
|
t2 = time.time()
|
|
log(
|
|
f"ResultatsSemestreBUT: cached formsemestre_id={formsemestre.id} ({(t1-t0):g}s +{(t2-t1):g}s)"
|
|
)
|
|
|
|
def compute(self):
|
|
"Charge les notes et inscriptions et calcule les moyennes d'UE et gen."
|
|
(
|
|
self.sem_cube,
|
|
self.modimpls_evals_poids,
|
|
self.modimpls_results,
|
|
) = moy_ue.notes_sem_load_cube(self.formsemestre)
|
|
self.modimpl_inscr_df = inscr_mod.df_load_modimpl_inscr(self.formsemestre)
|
|
self.modimpl_coefs_df, _, _ = moy_ue.df_load_modimpl_coefs(
|
|
self.formsemestre, modimpls=self.formsemestre.modimpls_sorted
|
|
)
|
|
# l'idx de la colonne du mod modimpl.id est
|
|
# modimpl_coefs_df.columns.get_loc(modimpl.id)
|
|
# idx de l'UE: modimpl_coefs_df.index.get_loc(ue.id)
|
|
|
|
# Masque de tous les modules _sauf_ les bonus (sport)
|
|
modimpls_mask = [
|
|
modimpl.module.ue.type != UE_SPORT
|
|
for modimpl in self.formsemestre.modimpls_sorted
|
|
]
|
|
|
|
self.etud_moy_ue = moy_ue.compute_ue_moys_apc(
|
|
self.sem_cube,
|
|
self.etuds,
|
|
self.formsemestre.modimpls_sorted,
|
|
self.ues,
|
|
self.modimpl_inscr_df,
|
|
self.modimpl_coefs_df,
|
|
modimpls_mask,
|
|
)
|
|
# Les coefficients d'UE ne sont pas utilisés en APC
|
|
self.etud_coef_ue_df = pd.DataFrame(
|
|
0.0, index=self.etud_moy_ue.index, columns=self.etud_moy_ue.columns
|
|
)
|
|
|
|
# --- Modules de MALUS sur les UEs
|
|
self.malus = moy_ue.compute_malus(
|
|
self.formsemestre, self.sem_cube, self.ues, self.modimpl_inscr_df
|
|
)
|
|
self.etud_moy_ue -= self.malus
|
|
|
|
# --- Bonus Sport & Culture
|
|
if not all(modimpls_mask): # au moins un module bonus
|
|
bonus_class = ScoDocSiteConfig.get_bonus_sport_class()
|
|
if bonus_class is not None:
|
|
bonus: BonusSport = bonus_class(
|
|
self.formsemestre,
|
|
self.sem_cube,
|
|
self.ues,
|
|
self.modimpl_inscr_df,
|
|
self.modimpl_coefs_df.transpose(),
|
|
self.etud_moy_gen,
|
|
self.etud_moy_ue,
|
|
)
|
|
self.bonus_ues = bonus.get_bonus_ues()
|
|
if self.bonus_ues is not None:
|
|
self.etud_moy_ue += self.bonus_ues # somme les dataframes
|
|
|
|
# Clippe toutes les moyennes d'UE dans [0,20]
|
|
self.etud_moy_ue.clip(lower=0.0, upper=20.0, inplace=True)
|
|
|
|
# Moyenne générale indicative:
|
|
# (note: le bonus sport a déjà été appliqué aux moyennes d'UE, et impacte
|
|
# donc la moyenne indicative)
|
|
# self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_coefs(
|
|
# self.etud_moy_ue, self.modimpl_coefs_df
|
|
# )
|
|
self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_ects(
|
|
self.etud_moy_ue,
|
|
[ue.ects for ue in self.ues if ue.type != UE_SPORT],
|
|
formation_id=self.formsemestre.formation_id,
|
|
)
|
|
# --- UE capitalisées
|
|
self.apply_capitalisation()
|
|
|
|
# --- Classements:
|
|
self.compute_rangs()
|
|
|
|
def get_etud_mod_moy(self, moduleimpl_id: int, etudid: int) -> float:
|
|
"""La moyenne de l'étudiant dans le moduleimpl
|
|
En APC, il s'agit d'une moyenne indicative sans valeur.
|
|
Result: valeur float (peut être naN) ou chaîne "NI" (non inscrit ou DEM)
|
|
"""
|
|
mod_idx = self.modimpl_coefs_df.columns.get_loc(moduleimpl_id)
|
|
etud_idx = self.etud_index[etudid]
|
|
# moyenne sur les UE:
|
|
if len(self.sem_cube[etud_idx, mod_idx]):
|
|
return np.nanmean(self.sem_cube[etud_idx, mod_idx])
|
|
return np.nan
|
|
|
|
def compute_etud_ue_coef(self, etudid: int, ue: UniteEns) -> float:
|
|
"""Détermine le coefficient de l'UE pour cet étudiant.
|
|
N'est utilisé que pour l'injection des UE capitalisées dans la
|
|
moyenne générale.
|
|
En BUT, c'est simple: Coef = somme des coefs des modules vers cette UE.
|
|
(ne dépend pas des modules auxquels est inscrit l'étudiant, ).
|
|
"""
|
|
return self.modimpl_coefs_df.loc[ue.id].sum()
|
|
|
|
def modimpls_in_ue(self, ue_id, etudid) -> list[ModuleImpl]:
|
|
"""Liste des modimpl ayant des coefs non nuls vers cette UE
|
|
et auxquels l'étudiant est inscrit.
|
|
"""
|
|
# sert pour l'affichage ou non de l'UE sur le bulletin
|
|
coefs = self.modimpl_coefs_df # row UE, cols modimpl
|
|
return [
|
|
modimpl
|
|
for modimpl in self.formsemestre.modimpls_sorted
|
|
if (coefs[modimpl.id][ue_id] != 0)
|
|
and self.modimpl_inscr_df[modimpl.id][etudid]
|
|
]
|