############################################################################## # ScoDoc # Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved. # See LICENSE ############################################################################## """Classes spécifiques de calcul du bonus sport, culture ou autres activités Les classes de Bonus fournissent deux méthodes: - get_bonus_ues() - get_bonus_moy_gen() """ import datetime import numpy as np import pandas as pd from flask import g from app.scodoc.codes_cursus import UE_SPORT, UE_STANDARD from app.scodoc.codes_cursus import CursusDUT, CursusDUTMono from app.scodoc.sco_utils import ModuleType class BonusSport: """Calcul du bonus sport. Arguments: - sem_modimpl_moys : notes moyennes aux modules (tous les étuds x tous les modimpls) floats avec des NaN. En classique: sem_matrix, ndarray (etuds x modimpls) En APC: sem_cube, ndarray (etuds x modimpls x UEs non bonus) - ues: les ues du semestre (incluant le bonus sport) - modimpl_inscr_df: matrice d'inscription aux modules du semestre (etud x modimpl) - modimpl_coefs: les coefs des modules En classique: 1d ndarray de float (modimpl) En APC: 2d ndarray de float, (modimpl x UE) <= attention à transposer - etud_moy_gen: Series, index etudid, valeur float (moyenne générale avant bonus) - etud_moy_ue: DataFrame columns UE (sans sport), rows etudid (moyennes avant bonus) etud_moy_gen et etud_moy_ue ne sont PAS modifiés (mais utilisés par certains bonus non additifs). """ # En classique, active un bonus sur les UEs: (dans ce cas bonus_moy_gen est ajusté pour le prendre en compte) classic_use_bonus_ues = False # Attributs virtuels: seuil_moy_gen = None proportion_point = None bonus_max = None name = "virtual" def __init__( self, formsemestre: "FormSemestre", sem_modimpl_moys: np.array, ues: list, modimpl_inscr_df: pd.DataFrame, modimpl_coefs: np.array, etud_moy_gen, etud_moy_ue, ): self.formsemestre = formsemestre self.ues = ues self.etud_moy_gen = etud_moy_gen self.etud_moy_ue = etud_moy_ue self.etuds_idx = modimpl_inscr_df.index # les étudiants inscrits au semestre self.bonus_ues: pd.DataFrame = None # virtual self.bonus_moy_gen: pd.Series = None # virtual (pour formations non apc slt) # Restreint aux modules standards des UE de type "sport": modimpl_mask = np.array( [ (m.module.module_type == ModuleType.STANDARD) and (m.module.ue.type == UE_SPORT) for m in formsemestre.modimpls_sorted ] ) if len(modimpl_mask) == 0: modimpl_mask = np.s_[:] # il n'y a rien, on prend tout donc rien self.modimpls_spo = [ modimpl for i, modimpl in enumerate(formsemestre.modimpls_sorted) if modimpl_mask[i] ] "liste des modimpls sport" # Les moyennes des modules "sport": (une par UE en APC) # donc (nb_etuds, nb_mod_sport, nb_ues_non_bonus) sem_modimpl_moys_spo = sem_modimpl_moys[:, modimpl_mask] # Les inscriptions aux modules sport: modimpl_inscr_spo = modimpl_inscr_df.values[:, modimpl_mask] # Les coefficients des modules sport (en apc: nb_mod_sport x nb_ue) (toutes ues) modimpl_coefs_spo = modimpl_coefs[modimpl_mask] # sem_modimpl_moys_spo est (nb_etuds, nb_mod_sport) # ou (nb_etuds, nb_mod_sport, nb_ues_non_bonus) nb_etuds, nb_mod_sport = sem_modimpl_moys_spo.shape[:2] if nb_etuds == 0 or nb_mod_sport == 0: return # no bonus at all # Enlève les NaN du numérateur: sem_modimpl_moys_no_nan = np.nan_to_num(sem_modimpl_moys_spo, nan=0.0) # Annule les coefs des modules où l'étudiant n'est pas inscrit: if formsemestre.formation.is_apc(): # BUT nb_ues_no_bonus = sem_modimpl_moys.shape[2] if nb_ues_no_bonus == 0: # aucune UE... return # no bonus at all # Duplique les inscriptions sur les UEs non bonus: modimpl_inscr_spo_stacked = np.stack( [modimpl_inscr_spo] * nb_ues_no_bonus, axis=2 ) # Ne prend pas en compte les notes des étudiants non inscrits au module: # Annule les notes: (nb_etuds, nb_mod_bonus, nb_ues_non_bonus) sem_modimpl_moys_inscrits = np.where( modimpl_inscr_spo_stacked, sem_modimpl_moys_no_nan, 0.0 ) # Annule les coefs des modules où l'étudiant n'est pas inscrit: modimpl_coefs_etuds = np.where( modimpl_inscr_spo_stacked, np.stack([modimpl_coefs_spo] * nb_etuds), 0.0, ) else: # Formations classiques # Ne prend pas en compte les notes des étudiants non inscrits au module: # Annule les notes: sem_modimpl_moys_inscrits = np.where( modimpl_inscr_spo, sem_modimpl_moys_no_nan, 0.0 ) modimpl_coefs_spo = modimpl_coefs_spo.T if nb_etuds == 0: modimpl_coefs_etuds = modimpl_inscr_spo # vide else: modimpl_coefs_etuds = np.where( modimpl_inscr_spo, np.stack([modimpl_coefs_spo] * nb_etuds), 0.0 ) # Annule les coefs des modules NaN (nb_etuds x nb_mod_sport) modimpl_coefs_etuds_no_nan = np.where( np.isnan(sem_modimpl_moys_spo), 0.0, modimpl_coefs_etuds ) # self.compute_bonus(sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan) def compute_bonus( self, sem_modimpl_moys_inscrits: np.ndarray, modimpl_coefs_etuds_no_nan: np.ndarray, ): """Calcul des bonus: méthode virtuelle à écraser. Arguments: - sem_modimpl_moys_inscrits: ndarray (nb_etuds, mod_sport) ou en APC (nb_etuds, mods_sport, nb_ue_non_bonus) les notes aux modules sports auxquel l'étudiant est inscrit, 0 sinon. Pas de nans. - modimpl_coefs_etuds_no_nan: les coefficients: float ndarray Résultat: None """ raise NotImplementedError("méthode virtuelle") def get_bonus_ues(self) -> pd.DataFrame: """Les bonus à appliquer aux UE Résultat: DataFrame de float, index etudid, columns: ue.id """ if self.classic_use_bonus_ues or self.formsemestre.formation.is_apc(): return self.bonus_ues return None def get_bonus_moy_gen(self): """Le bonus à appliquer à la moyenne générale. Résultat: Series de float, index etudid """ if self.formsemestre.formation.is_apc(): return None # garde-fou return self.bonus_moy_gen class BonusSportAdditif(BonusSport): """Bonus sport simples calcule un bonus à partir des notes moyennes de modules de l'UE sport, et ce bonus est soit ajouté à la moyenne générale (formations classiques), soit ajouté à chaque UE (formations APC). Le bonus est par défaut calculé comme: Les points au-dessus du seuil (par défaut) 10 sur 20 obtenus dans chacun des modules optionnels sont cumulés et une fraction de ces points cumulés s'ajoute à la moyenne générale du semestre déjà obtenue par l'étudiant. """ seuil_moy_gen = 10.0 # seuls les bonus au dessus du seuil sont pris en compte # les points au dessus du seuil sont comptés (defaut: seuil_moy_gen): seuil_comptage = None proportion_point = 0.05 # multiplie les points au dessus du seuil bonus_max = 20.0 # le bonus ne peut dépasser 20 points bonus_min = 0.0 # et ne peut pas être négatif def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus sem_modimpl_moys_inscrits: les notes de sport En APC: ndarray (nb_etuds, nb_mod_sport, nb_ues_non_bonus) En classic: ndarray (nb_etuds, nb_mod_sport) modimpl_coefs_etuds_no_nan: même shape, les coefs. """ if 0 in sem_modimpl_moys_inscrits.shape: # pas d'étudiants ou pas d'UE ou pas de module... return seuil_comptage = ( self.seuil_moy_gen if self.seuil_comptage is None else self.seuil_comptage ) bonus_moy_arr = np.sum( np.where( (sem_modimpl_moys_inscrits >= self.seuil_moy_gen) & (modimpl_coefs_etuds_no_nan > 0), (sem_modimpl_moys_inscrits - seuil_comptage) * self.proportion_point, 0.0, ), axis=1, ) # Seuil: bonus dans [min, max] (défaut [0,20]) bonus_max = self.bonus_max or 20.0 np.clip(bonus_moy_arr, self.bonus_min, bonus_max, out=bonus_moy_arr) self.bonus_additif(bonus_moy_arr) def bonus_additif(self, bonus_moy_arr: np.array): "Set bonus_ues et bonus_moy_gen" # en APC, bonus_moy_arr est (nb_etuds, nb_ues_non_bonus) if self.formsemestre.formation.is_apc(): # Bonus sur les UE et None sur moyenne générale ues_idx = [ue.id for ue in self.formsemestre.get_ues(with_sport=False)] self.bonus_ues = pd.DataFrame( bonus_moy_arr, index=self.etuds_idx, columns=ues_idx, dtype=float ) elif self.classic_use_bonus_ues: # Formations classiques apppliquant le bonus sur les UEs # ici bonus_moy_arr = ndarray 1d nb_etuds ues_idx = [ue.id for ue in self.formsemestre.get_ues(with_sport=False)] self.bonus_ues = pd.DataFrame( np.stack([bonus_moy_arr] * len(ues_idx)).T, index=self.etuds_idx, columns=ues_idx, dtype=float, ) else: # Bonus sur la moyenne générale seulement self.bonus_moy_gen = pd.Series( bonus_moy_arr, index=self.etuds_idx, dtype=float ) class BonusSportMultiplicatif(BonusSport): """Bonus sport qui multiplie les moyennes d'UE par un facteur""" seuil_moy_gen = 10.0 # seuls les points au dessus du seuil sont comptés amplitude = 0.005 # multiplie les points au dessus du seuil # En classique, les bonus multiplicatifs agissent par défaut sur les UE: classic_use_bonus_ues = True # Facteur multiplicatif max: (bonus = moy_ue*factor) factor_max = 1000.0 # infini # C'est un bonus "multiplicatif": on l'exprime en additif, # sur chaque moyenne d'UE m_0 # Augmenter de 5% correspond à multiplier par a=1.05 # m_1 = a . m_0 # m_1 = m_0 + bonus # bonus = m_0 (a - 1) def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus""" if 0 in sem_modimpl_moys_inscrits.shape: # pas d'étudiants ou pas d'UE ou pas de module... return # Calcule moyenne pondérée des notes de sport: notes = np.sum( sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1 ) / np.sum(modimpl_coefs_etuds_no_nan, axis=1) notes = np.nan_to_num(notes, copy=False) factor = (notes - self.seuil_moy_gen) * self.amplitude # 5% si note=20 factor[factor <= 0] = 0.0 # note < seuil_moy_gen, pas de bonus # note < seuil_moy_gen, pas de bonus: pas de facteur négatif, ni factor.clip(0.0, self.factor_max, out=factor) # Ne s'applique qu'aux moyennes d'UE if len(factor.shape) == 1: # classic factor = factor[:, np.newaxis] bonus = self.etud_moy_ue * factor if self.bonus_max is not None: # Seuil: bonus limité à bonus_max points bonus.clip(upper=self.bonus_max, inplace=True) self.bonus_ues = bonus # DataFrame # Les bonus multiplicatifs ne s'appliquent pas à la moyenne générale self.bonus_moy_gen = None class BonusDirect(BonusSportAdditif): """Bonus direct: les points sont directement ajoutés à la moyenne générale. Les coefficients sont ignorés: tous les points de bonus sont sommés. (rappel: la note est ramenée sur 20 avant application). """ name = "bonus_direct" displayed_name = 'Bonus "direct"' seuil_moy_gen = 0.0 # tous les points sont comptés proportion_point = 1.0 class BonusAisneStQuentin(BonusSportAdditif): """Calcul bonus modules optionels (sport, culture), règle IUT Aisne St Quentin
Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'Université de St Quentin non rattachés à une unité d'enseignement.
Ce bonus s'ajoute à la moyenne générale du semestre déjà obtenue par l'étudiant (en BUT, s'ajoute à la moyenne de chaque UE).
""" name = "bonus_iutstq" displayed_name = "IUT de Saint-Quentin" def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus""" if 0 in sem_modimpl_moys_inscrits.shape: # pas d'étudiants ou pas d'UE ou pas de module... return # Calcule moyenne pondérée des notes de sport: with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN) bonus_moy_arr = np.sum( sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1 ) / np.sum(modimpl_coefs_etuds_no_nan, axis=1) np.nan_to_num(bonus_moy_arr, nan=0.0, copy=False) bonus_moy_arr[bonus_moy_arr < 10.0] = 0.0 bonus_moy_arr[bonus_moy_arr >= 18.1] = 0.5 bonus_moy_arr[bonus_moy_arr >= 16.1] = 0.4 bonus_moy_arr[bonus_moy_arr >= 14.1] = 0.3 bonus_moy_arr[bonus_moy_arr >= 12.1] = 0.2 bonus_moy_arr[bonus_moy_arr >= 10] = 0.1 self.bonus_additif(bonus_moy_arr) class BonusAmiens(BonusSportAdditif): """Bonus IUT Amiens pour les modules optionnels (sport, culture, ...)À partir d'août 2022:
Deux activités optionnelles sont possibles chaque semestre, et peuvent donner lieu à une bonification de 0,1 chacune sur la moyenne de chaque UE.
La note saisie peut valoir 0 (pas de bonus), 1 (bonus de 0,1 points) ou 2 (bonus de 0,2 points).
Avant juillet 2022:
Toute note non nulle, peu importe sa valeur, entraine un bonus de 0,1 point sur toutes les moyennes d'UE.
""" name = "bonus_amiens" displayed_name = "IUT d'Amiens" classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP seuil_moy_gen = 0.0 # tous les points sont comptés def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus, avec réglage différent suivant la date""" if self.formsemestre.date_debut > datetime.date(2022, 8, 1): self.proportion_point = 0.1 self.bonus_max = 0.2 else: # anciens semestres self.proportion_point = 1e10 self.bonus_max = 0.1 super().compute_bonus(sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan) # Finalement ils n'en veulent pas. # class BonusAnnecy(BonusSport): # """Calcul bonus modules optionnels (sport), règle IUT d'Annecy. # Il peut y avoir plusieurs modules de bonus. # Prend pour chaque étudiant la meilleure de ses notes bonus et # ajoute à chaque UE :Le bonus est compris entre 0 et 0,2 points. et est reporté sur les moyennes d'UE.
La valeur saisie doit être entre 0 et 0,2: toute valeur supérieure à 0,2 entraine un bonus de 0,2.
""" name = "bonus_besancon_vesoul" displayed_name = "IUT de Besançon - Vesoul" classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP seuil_moy_gen = 0.0 # tous les points sont comptés proportion_point = 1 bonus_max = 0.2 class BonusBethune(BonusSportMultiplicatif): """ Calcul bonus modules optionnels (sport, culture), règle IUT de Béthune.Pour le BUT : La note de sport est sur 20, et on calcule une bonification (en %) qui va s'appliquer à la moyenne de chaque UE du semestre en appliquant la formule : bonification (en %) = max(note-10, 0)*(1/500).
La bonification ne s'applique que si la note est supérieure à 10.
(Une note de 10 donne donc 0% de bonif, 1 point au dessus de 10 augmente la moyenne des UE de 0.2%)
Pour le DUT/LP : La note de sport est sur 20, et on calcule une bonification (en %) qui va s'appliquer à la moyenne générale du semestre en appliquant la formule : bonification (en %) = max(note-10, 0)*(1/200).
La bonification ne s'applique que si la note est supérieure à 10.
(Une note de 10 donne donc 0% de bonif, 1 point au dessus de 10 augmente la moyenne des UE de 0.5%)
""" name = "bonus_iutbethune" displayed_name = "IUT de Béthune" seuil_moy_gen = 10.0 # points comptés au dessus de 10. def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus""" if self.formsemestre.formation.is_apc(): self.amplitude = 0.002 else: self.amplitude = 0.005 return super().compute_bonus( sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan ) class BonusBezier(BonusSportAdditif): """Calcul bonus modules optionnels (sport, culture), règle IUT de Bézier. Les étudiants de l'IUT peuvent suivre des enseignements optionnels sport , etc) non rattachés à une unité d'enseignement. Les points au-dessus de 10 sur 20 obtenus dans chacune des matières optionnelles sont cumulés et 3% de ces points cumulés s'ajoutent à la moyenne générale du semestre déjà obtenue par l'étudiant, dans la limite de 0,3 points. """ # note: cela revient à dire que l'on ajoute 5% des points au dessus de 10, # et qu'on limite à 5% de 10, soit 0.5 points # ce bonus est donc strictement identique à celui de St Denis (BonusIUTStDenis) name = "bonus_iutbeziers" displayed_name = "IUT de Bézier" bonus_max = 0.3 seuil_moy_gen = 10.0 # tous les points sont comptés proportion_point = 0.03 class BonusBlagnac(BonusSportAdditif): """Calcul bonus modules optionnels (sport, culture), règle IUT de Blagnac. Le bonus est égal à 5% des points au dessus de 10 à appliquer sur toutes les UE du semestre, applicable dans toutes les formations (DUT, BUT, ...). """ name = "bonus_iutblagnac" displayed_name = "IUT de Blagnac" proportion_point = 0.05 classic_use_bonus_ues = True # toujours sur les UE class BonusBordeaux1(BonusSportMultiplicatif): """Calcul bonus modules optionnels (sport, culture), règle IUT Bordeaux 1, sur moyenne générale et UEs.Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'Université Bordeaux 1 (sport, théâtre) non rattachés à une unité d'enseignement.
Chaque point au-dessus de 10 sur 20 obtenus dans cet enseignement correspond à un %
qui augmente la moyenne de chaque UE et la moyenne générale.
Formule : pourcentage = (points au dessus de 10) / 2
Par exemple : sport 13/20 : chaque UE sera multipliée par 1+0,015, ainsi que la moyenne générale.
""" name = "bonus_iutBordeaux1" displayed_name = "IUT de Bordeaux" classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP seuil_moy_gen = 10.0 amplitude = 0.005 # Exactement le même que Bordeaux: class BonusBrest(BonusSportMultiplicatif): """Calcul bonus modules optionnels (sport, culture), règle IUT de Brest, sur moyenne générale et UEs.Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'Université (sport, théâtre) non rattachés à une unité d'enseignement.
Chaque point au-dessus de 10 sur 20 obtenus dans cet enseignement correspond à un %
qui augmente la moyenne de chaque UE et la moyenne générale.
Formule : pourcentage = (points au dessus de 10) / 2
Par exemple : sport 13/20 : chaque UE sera multipliée par 1+0,015, ainsi que la moyenne générale.
""" name = "bonus_iut_brest" displayed_name = "IUT de Brest" classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP seuil_moy_gen = 10.0 amplitude = 0.005 class BonusCachan1(BonusSportAdditif): """Calcul bonus optionnels (sport, culture), règle IUT de Cachan 1.À compter de sept. 2021: La note de sport est sur 20, et on calcule une bonification (en %) qui va s'appliquer à la moyenne de chaque UE du semestre en appliquant la formule : bonification (en %) = (note-10)*0,5.
La bonification ne s'applique que si la note est supérieure à 10.
(Une note de 10 donne donc 0% de bonif, et une note de 20 : 5% de bonif)
Avant sept. 2021, la note de sport allait de 0 à 5 points (sur 20). Chaque point correspondait à 0.25% d'augmentation de la moyenne générale. Par exemple : note de sport 2/5 : la moyenne générale était augmentée de 0.5%.
""" name = "bonus_iut1grenoble_2017" displayed_name = "IUT de Grenoble 1" # C'est un bonus "multiplicatif": on l'exprime en additif, # sur chaque moyenne d'UE m_0 # Augmenter de 5% correspond à multiplier par a=1.05 # m_1 = a . m_0 # m_1 = m_0 + bonus # bonus = m_0 (a - 1) def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus, avec réglage différent suivant la date""" if self.formsemestre.date_debut > datetime.date(2021, 7, 15): self.seuil_moy_gen = 10.0 self.amplitude = 0.005 else: # anciens semestres self.seuil_moy_gen = 0.0 self.amplitude = 1 / 400.0 super().compute_bonus(sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan) class BonusIUTRennes1(BonusSportAdditif): """Calcul bonus optionnels (sport, langue vivante, engagement étudiant), règle IUT de l'Université de Rennes 1 (Lannion, Rennes, St Brieuc, St Malo).Article 5 : Bonification des activités hors programmes nationaux :
Pour calculer la moyenne M de chaque UE des semestres pairs, il convient d'ajouter la validation de note obtenue qui s'effectuera suivant la formule :
M = Mo + ((S-10)/10)/(Nombre d'UE du semestre)où Mo est la moyenne de l'UE avant prise en compte de la note et S est la note finale attribuée par l'activité bonifiée (si S > 10).
Sont éligibles à cette bonification une activité sportive dans le cadre universitaire, une langue vivante optionnelle et l'engagement étudiant (dans le cadre défini par la commission de la formation et de la vie universitaire (CFVE) de l'Université de Rennes annexe 3).
Pour l'étudiant pouvant prétendre à plusieurs bonifications, seule la meilleure des notes sera prise en compte. Toutefois, une bonification liée à l'engagement est cumulable avec une autre bonification.
La note saisie s'applique directement: si on saisit 0,2, un bonus de 0,2 points est appliqué aux moyennes. La valeur maximale du bonus est 1 point. Il est appliqué sur les moyennes d'UEs en BUT, ou sur la moyenne générale dans les autres formations.
Pour les semestres antérieurs à janvier 2023: si une note de bonus est saisie, l'étudiant est gratifié de 0,2 points sur sa moyenne générale ou, en BUT, sur la moyenne de chaque UE.
""" name = "bonus_larochesuryon" displayed_name = "IUT de La Roche-sur-Yon" seuil_moy_gen = 0.0 seuil_comptage = 0.0 def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus, avec réglage différent suivant la date""" if self.formsemestre.date_debut > datetime.date(2022, 12, 31): self.proportion_point = 1.0 self.bonus_max = 1 else: # ancienne règle self.proportion_point = 1e10 # le moindre point sature le bonus self.bonus_max = 0.2 # à 0.2 super().compute_bonus(sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan) class BonusLaRochelle(BonusSportAdditif): """Calcul bonus modules optionnels (sport, culture), règle IUT de La Rochelle.Les enseignements optionnels de langue, préprofessionnalisation, PIX (compétences numériques), l'entrepreneuriat étudiant, l'engagement bénévole au sein d'association dès lors qu'une grille d'évaluation des compétences existe ainsi que les activités sportives et culturelles seront traités au niveau semestriel.
Le maximum de bonification qu'un étudiant peut obtenir sur sa moyenne est plafonné à 0.5 point.
Lorsqu'un étudiant suit plus de deux matières qui donnent droit à bonification, l'étudiant choisit les deux notes à retenir.
Les points bonus ne sont acquis que pour une note supérieure à 10/20.
La bonification est calculée de la manière suivante :
Pour chaque matière (max. 2) donnant lieu à bonification :
Bonification = (N-10) x 0,05,
N étant la note de l'activité sur 20.
Les points au-dessus de 10 sur 20 obtenus dans chacune des matières optionnelles sont cumulés.
Dans tous les cas, le bonus est dans la limite de 0,5 point.
""" name = "bonus_iutlemans" displayed_name = "IUT du Mans" seuil_moy_gen = 10.0 # points comptés au dessus de 10. bonus_max = 0.5 # def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus""" # La date du semestre ? if self.formsemestre.formation.is_apc(): self.proportion_point = 0.02 else: self.proportion_point = 0.05 return super().compute_bonus( sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan ) # Bonus simple, mais avec changement de paramètres en 2010 ! class BonusLille(BonusSportAdditif): """Calcul bonus modules optionnels (sport, culture), règle IUT Villeneuve d'AscqLes étudiants de l'IUT peuvent suivre des enseignements optionnels de l'Université Lille (sports, etc) non rattachés à une unité d'enseignement.
Les points au-dessus de 10 sur 20 obtenus dans chacune des matières optionnelles sont cumulés et 4% (2% avant août 2010) de ces points cumulés s'ajoutent à la moyenne générale du semestre déjà obtenue par l'étudiant.
""" name = "bonus_lille" displayed_name = "IUT de Lille" seuil_moy_gen = 10.0 # points comptés au dessus de 10. def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus""" # La date du semestre ? if self.formsemestre.date_debut > datetime.date(2010, 8, 1): self.proportion_point = 0.04 else: self.proportion_point = 0.02 return super().compute_bonus( sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan ) class BonusLimousin(BonusSportAdditif): """Calcul bonus modules optionnels (sport, culture) à l'IUT du Limousin Les points au-dessus de 10 sur 20 obtenus dans chacune des matières optionnelles sont cumulés. La moyenne de chacune des UE du semestre pair est augmentée de 5% du cumul des points de bonus. Le maximum de points bonus est de 0,5. """ name = "bonus_limousin" displayed_name = "IUT du Limousin" proportion_point = 0.05 bonus_max = 0.5 class BonusLyon(BonusSportAdditif): """Calcul bonus modules optionnels (sport, culture) à l'IUT de Lyon (2022)À partir de 2022-2023 :
des points de bonification seront ajoutés aux moyennes de toutes les UE
du semestre concerné (3/100e de point par point au-dessus de 10).
Cette bonification ne pourra excéder 1/2 point sur chacune des UE
Jusqu'en 2021-2022 : Les points au-dessus de 10 sur 20 obtenus dans chacune des matières optionnelles sont cumulés et 1,8% de ces points cumulés s'ajoutent aux moyennes générales, dans la limite d'1/2 point.
""" name = "bonus_lyon_provisoire" displayed_name = "IUT de Lyon" seuil_moy_gen = 10.0 # points comptés au dessus de 10. bonus_max = 0.5 def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): if self.formsemestre.date_debut > datetime.date(2022, 8, 1): self.classic_use_bonus_ues = True # pour les LP self.proportion_point = 0.03 else: self.classic_use_bonus_ues = False self.proportion_point = 0.018 return super().compute_bonus( sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan ) class BonusLyon3(BonusSportAdditif): """IUT de Lyon 3 (septembre 2022)Nous avons deux types de bonifications : sport et/ou culture
Pour chaque point au-dessus de 10 obtenu en sport ou en culture nous ajoutons 0,03 points à toutes les moyennes d’UE du semestre. Exemple : 16 en sport ajoute 6*0,03 = 0,18 points à toutes les moyennes d’UE du semestre.
Les bonifications sport et culture peuvent se cumuler dans la limite de 0,3 points ajoutés aux moyennes des UE. Exemple : 17 en sport et 16 en culture conduisent au calcul (7 + 6)*0,03 = 0,39 qui dépasse 0,3. La bonification dans ce cas ne sera que de 0,3 points ajoutés à toutes les moyennes d’UE du semestre.
Dans Scodoc on déclarera une UE Sport&Culture dans laquelle on aura un module pour le Sport et un autre pour la Culture avec pour chaque module la note sur 20 obtenue en sport ou en culture par l’étudiant.
""" name = "bonus_lyon3" displayed_name = "IUT de Lyon 3" proportion_point = 0.03 bonus_max = 0.3 class BonusMantes(BonusSportAdditif): """Calcul bonus modules optionnels (investissement, ...), IUT de Mantes en Yvelines.Soit N la note attribuée, le bonus (ou malus) correspond à : (N-10) x 0,05 appliqué sur chaque UE du semestre sélectionné pour le BUT ou appliqué sur la moyenne générale du semestre sélectionné pour le DUT.
Exemples :
Nous avons différents types de bonification (sport, culture, engagement citoyen).
Nous ajoutons aux moyennes une bonification de 0,2 pour chaque item la bonification totale ne doit pas excéder les 0,5 point. Sur le bulletin nous ne mettons pas une note sur 20 mais directement les bonifications.
Dans ScoDoc: on a déclarera une UE "sport&culture" dans laquelle on aura des modules pour chaque activité (Sport, Associations, ...) avec à chaque fois une note (ScoDoc l'affichera comme une note sur 20, mais en fait ce sera la valeur de la bonification: entrer 0,1/20 signifiera un bonus de 0,1 point la moyenne générale).
""" name = "bonus_nantes" displayed_name = "IUT de Nantes" seuil_moy_gen = 0.0 # seuls les points au dessus du seuil sont comptés proportion_point = 1 # multiplie les points au dessus du seuil bonus_max = 0.5 # plafonnement à 0.5 points class BonusOrleans(BonusSportAdditif): """Calcul bonus modules optionnels (sport, culture), règle IUT d'OrléansCadre général : En reconnaissance de l'engagement des étudiants dans la vie associative, sociale ou professionnelle, l'IUT d'Orléans accorde, sous conditions, une bonification aux étudiants inscrits qui en font la demande en début d'année universitaire.
Cet engagement doit être régulier et correspondre à une activité réelle et sérieuse qui bénéficie à toute la communauté étudiante de l'IUT, de l'Université ou à l'ensemble de la collectivité.
Bonification : Pour les DUT et LP, cette bonification interviendra sur la moyenne générale des semestres pairs :
Avant février 2020 : Un bonus de 2,5% de la note de sport est accordé à la moyenne générale.
""" name = "bonus_iutorleans" displayed_name = "IUT d'Orléans" bonus_max = 0.5 seuil_moy_gen = 0.0 # seuls les points au dessus du seuil sont comptés proportion_point = 1 classic_use_bonus_ues = False def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): if self.formsemestre.date_debut > datetime.date(2020, 2, 1): self.proportion_point = 1.0 else: self.proportion_point = 2.5 / 100.0 return super().compute_bonus( sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan ) class BonusPoitiers(BonusSportAdditif): """Calcul bonus optionnels (sport, culture), règle IUT de Poitiers. Les deux notes d'option supérieure à 10, bonifient les moyennes de chaque UE. bonus = (option1 - 10)*5% + (option2 - 10)*5% """ name = "bonus_poitiers" displayed_name = "IUT de Poitiers" proportion_point = 0.05 class BonusRoanne(BonusSportAdditif): """IUT de Roanne. Le bonus est compris entre 0 et 0.6 points et est toujours appliqué aux UEs. """ name = "bonus_iutr" displayed_name = "IUT de Roanne" seuil_moy_gen = 0.0 bonus_max = 0.6 # plafonnement à 0.6 points classic_use_bonus_ues = True # sur les UE, même en DUT et LP proportion_point = 1 class BonusSceaux(BonusSportAdditif): # atypique """IUT de Sceaux L’IUT de Sceaux (Université de Paris-Saclay) propose aux étudiants un seul enseignement non rattaché aux UE : l’option Sport.Cette option donne à l’étudiant qui la suit une bonification qui s’applique uniquement si sa note est supérieure à 10.
Cette bonification s’applique sur l’ensemble des UE d’un semestre de la façon suivante :
[ (Note – 10) / Nb UE du semestre ] / Total des coefficients de chaque UE
Exemple : un étudiant qui a obtenu 16/20 à l’option Sport en S1 (composé par exemple de 3 UE:UE1.1, UE1.2 et UE1.3) aurait les bonifications suivantes :
Exemple: une moyenne d'UE de 10/20 avec un total des bonus de 6% donne une moyenne de 10,6.
Les bonifications s'appliquent aussi au classement général du semestre et de l'année.
""" name = "bonus_iutSN" displayed_name = "IUT de Saint-Nazaire" classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP amplitude = 0.01 / 4 # 4pt => 1% factor_max = 0.1 # 10% max # Modifié 2022-11-29: calculer chaque bonus # (de 1 à 3 modules) séparément. def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """Calcul du bonus St Nazaire 2022 sem_modimpl_moys_inscrits: les notes de sport En APC: ndarray (nb_etuds, nb_mod_sport, nb_ues_non_bonus) En classic: ndarray (nb_etuds, nb_mod_sport) """ if 0 in sem_modimpl_moys_inscrits.shape: # pas d'étudiants ou pas d'UE ou pas de module... return # Prend les 3 premiers bonus trouvés # ignore les coefficients bonus_mod_moys = sem_modimpl_moys_inscrits[:, :3] bonus_mod_moys = np.nan_to_num(bonus_mod_moys, copy=False) factor = bonus_mod_moys * self.amplitude # somme les bonus: factor = factor.sum(axis=1) # et limite à 10%: factor.clip(0.0, self.factor_max, out=factor) # Applique aux moyennes d'UE if len(factor.shape) == 1: # classic factor = factor[:, np.newaxis] bonus = self.etud_moy_ue * factor self.bonus_ues = bonus # DataFrame # Les bonus multiplicatifs ne s'appliquent pas à la moyenne générale self.bonus_moy_gen = None class BonusTarbes(BonusIUTRennes1): """Calcul bonus optionnels (sport, culture), règle IUT de Tarbes.Les notes des UE bonus (ramenées sur 20) sont sommées et 1/40 (2,5%) est ajouté aux moyennes: soit à la moyenne générale, soit pour le BUT à chaque moyenne d'UE.
Attention: en GEII, facteur 1/40, ailleurs facteur 1.
Le bonus total est limité à 1 point.
""" name = "bonus_tours" displayed_name = "IUT de Tours" bonus_max = 1.0 # seuil_moy_gen = 0.0 # seuls les points au dessus du seuil sont comptés proportion_point = 1.0 / 40.0 def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul différencié selon le département !""" if g.scodoc_dept == "GEII": self.proportion_point = 1.0 / 40.0 else: self.proportion_point = 1.0 return super().compute_bonus( sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan ) class BonusIUTvannes(BonusSportAdditif): """Calcul bonus modules optionels (sport, culture), règle IUT VannesNe concerne actuellement que les DUT et LP
Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'U.B.S. (sports, musique, deuxième langue, culture, etc) non rattachés à une unité d'enseignement.
Les points au-dessus de 10 sur 20 obtenus dans chacune des matières optionnelles sont cumulés.
3% de ces points cumulés s'ajoutent à la moyenne générale du semestre déjà obtenue par l'étudiant.
""" name = "bonus_iutvannes" displayed_name = "IUT de Vannes" seuil_moy_gen = 10.0 proportion_point = 0.03 # 3% classic_use_bonus_ues = False # seulement sur moy gen. class BonusValenciennes(BonusDirect): """Article 7 des RCC de l'IUT de ValenciennesUne bonification maximale de 0.25 point (1/4 de point) peut être ajoutée à la moyenne de chaque Unité d'Enseignement pour :
Une bonification accordée par la commission des sports de l'UPHF peut être attribuée aux sportifs de haut niveau. Cette bonification est appliquée à l'ensemble des Unités d'Enseignement. Ce bonus est :
Le cumul de bonifications est possible mais ne peut excéder 0.5 point (un demi-point).
Dans ScoDoc, saisir directement la valeur désirée du bonus dans une évaluation notée sur 20.
""" name = "bonus_valenciennes" displayed_name = "IUT de Valenciennes" bonus_max = 0.5 class BonusVilleAvray(BonusSportAdditif): """Bonus modules optionnels (sport, culture), règle IUT Ville d'Avray. Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'Université Paris 10 (C2I) non rattachés à une unité d'enseignement.Ce bonus s'ajoute à la moyenne générale du semestre déjà obtenue par l'étudiant.
""" name = "bonus_iutva" displayed_name = "IUT de Ville d'Avray" def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus""" if 0 in sem_modimpl_moys_inscrits.shape: # pas d'étudiants ou pas d'UE ou pas de module... return # Calcule moyenne pondérée des notes de sport: with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN) bonus_moy_arr = np.sum( sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1 ) / np.sum(modimpl_coefs_etuds_no_nan, axis=1) np.nan_to_num(bonus_moy_arr, nan=0.0, copy=False) bonus_moy_arr[bonus_moy_arr < 10.0] = 0.0 bonus_moy_arr[bonus_moy_arr >= 16.0] = 0.3 bonus_moy_arr[bonus_moy_arr >= 12.0] = 0.2 bonus_moy_arr[bonus_moy_arr >= 10.0] = 0.1 self.bonus_additif(bonus_moy_arr) class BonusIUTV(BonusSportAdditif): """Calcul bonus modules optionnels (sport, culture), règle IUT Villetaneuse Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'Université Paris 13 (sports, musique, deuxième langue, culture, etc) non rattachés à une unité d'enseignement. Les points au-dessus de 10 sur 20 obtenus dans chacune des matières optionnelles sont cumulés et 5% de ces points cumulés s'ajoutent à la moyenne générale du semestre déjà obtenue par l'étudiant. """ name = "bonus_iutv" displayed_name = "IUT de Villetaneuse" # c'est le bonus par défaut: aucune méthode à surcharger # Finalement inutile: un bonus direct est mieux adapté à leurs besoins. # # class BonusMastersUSPNIG(BonusSportAdditif): # """Calcul bonus modules optionnels (sport, culture), règle Masters de l'Institut Galilée (USPN) # Les étudiants peuvent suivre des enseignements optionnels # de l'USPN (sports, musique, deuxième langue, culture, etc) dans une # UE libre. Les points au-dessus de 10 sur 20 obtenus dans cette UE # libre sont ajoutés au total des points obtenus pour les UE obligatoires # du semestre concerné. # """ # name = "bonus_masters__uspn_ig" # displayed_name = "Masters de l'Institut Galilée (USPN)" # proportion_point = 1.0 # seuil_moy_gen = 10.0 # def __init__( # self, # formsemestre: "FormSemestre", # sem_modimpl_moys: np.array, # ues: list, # modimpl_inscr_df: pd.DataFrame, # modimpl_coefs: np.array, # etud_moy_gen, # etud_moy_ue, # ): # # Pour ce bonus, il nous faut la somme des coefs des modules non bonus # # du formsemestre (et non auxquels les étudiants sont inscrits !) # self.sum_coefs = sum( # [ # m.module.coefficient # for m in formsemestre.modimpls_sorted # if (m.module.module_type == ModuleType.STANDARD) # and (m.module.ue.type == UE_STANDARD) # ] # ) # super().__init__( # formsemestre, # sem_modimpl_moys, # ues, # modimpl_inscr_df, # modimpl_coefs, # etud_moy_gen, # etud_moy_ue, # ) # # Bonus sur la moyenne générale seulement # # On a dans bonus_moy_arr le bonus additif classique # # Sa valeur sera appliquée comme moy_gen += bonus_moy_gen # # or ici on veut # # moy_gen = (somme des notes + bonus_moy_arr) / somme des coefs # # moy_gen += bonus_moy_arr / somme des coefs # self.bonus_moy_gen = ( # None if self.bonus_moy_gen is None else self.bonus_moy_gen / self.sum_coefs # ) def get_bonus_class_dict(start=BonusSport, d=None): """Dictionnaire des classes de bonus (liste les sous-classes de BonusSport ayant un nom) Resultat: { name : class } """ if d is None: d = {} if start.name != "virtual": d[start.name] = start for subclass in start.__subclasses__(): get_bonus_class_dict(subclass, d=d) return d