bonus: refactoring + Le Havre, Nantes, Roanne

This commit is contained in:
Emmanuel Viennet 2022-01-26 23:46:46 +01:00
parent 8473270ee6
commit b8abc846c6

View File

@ -16,12 +16,7 @@ import datetime
import numpy as np import numpy as np
import pandas as pd import pandas as pd
from app import db
from app import models
from app.models import UniteEns, Module, ModuleImpl, ModuleUECoef
from app.comp import moy_mod
from app.models.formsemestre import FormSemestre from app.models.formsemestre import FormSemestre
from app.scodoc import bonus_sport
from app.scodoc.sco_codes_parcours import UE_SPORT from app.scodoc.sco_codes_parcours import UE_SPORT
from app.scodoc.sco_utils import ModuleType from app.scodoc.sco_utils import ModuleType
@ -57,6 +52,8 @@ class BonusSport:
# Si vrai, en APC, si le bonus UE est None, reporte le bonus moy gen: # Si vrai, en APC, si le bonus UE est None, reporte le bonus moy gen:
apc_apply_bonus_mg_to_ues = True apc_apply_bonus_mg_to_ues = True
# Si True, reporte toujours le bonus moy gen sur les UE (même en formations classiques)
apply_bonus_mg_to_ues = False
# Attributs virtuels: # Attributs virtuels:
seuil_moy_gen = None seuil_moy_gen = None
proportion_point = None proportion_point = None
@ -167,10 +164,9 @@ class BonusSport:
"""Les bonus à appliquer aux UE """Les bonus à appliquer aux UE
Résultat: DataFrame de float, index etudid, columns: ue.id Résultat: DataFrame de float, index etudid, columns: ue.id
""" """
if ( if self.bonus_ues is None and (
self.formsemestre.formation.is_apc() (self.apc_apply_bonus_mg_to_ues and self.formsemestre.formation.is_apc())
and self.apc_apply_bonus_mg_to_ues or self.apply_bonus_mg_to_ues
and self.bonus_ues is None
): ):
# reporte uniformément le bonus moyenne générale sur les UEs # reporte uniformément le bonus moyenne générale sur les UEs
# (assure la compatibilité de la plupart des anciens bonus avec le BUT) # (assure la compatibilité de la plupart des anciens bonus avec le BUT)
@ -189,10 +185,10 @@ class BonusSport:
return self.bonus_moy_gen return self.bonus_moy_gen
class BonusSportSimples(BonusSport): class BonusSportAdditif(BonusSport):
"""Les bonus sport simples calcule un bonus à partir des notes moyennes de modules """Bonus sport simples calcule un bonus à partir des notes moyennes de modules
de l'UE sport, et ce bonus est soit appliqué sur la moyenne générale (formations classiques), de l'UE sport, et ce bonus est soit ajouté à la moyenne générale (formations classiques),
soit réparti sur les UE (formations APC). soit ajouté à chaque UE (formations APC).
Le bonus est par défaut calculé comme: Le bonus est par défaut calculé comme:
Les points au-dessus du seuil (par défaut) 10 sur 20 obtenus dans chacun des Les points au-dessus du seuil (par défaut) 10 sur 20 obtenus dans chacun des
@ -231,7 +227,7 @@ class BonusSportSimples(BonusSport):
# bonus_ue = np.stack([modimpl_coefs_spo.T] * nb_ues) # bonus_ue = np.stack([modimpl_coefs_spo.T] * nb_ues)
class BonusIUTV(BonusSportSimples): class BonusIUTV(BonusSportAdditif):
"""Calcul bonus modules optionels (sport, culture), règle IUT Villetaneuse """Calcul bonus modules optionels (sport, culture), règle IUT Villetaneuse
Les étudiants de l'IUT peuvent suivre des enseignements optionnels Les étudiants de l'IUT peuvent suivre des enseignements optionnels
@ -246,7 +242,7 @@ class BonusIUTV(BonusSportSimples):
pass # oui, c'ets le bonus par défaut pass # oui, c'ets le bonus par défaut
class BonusDirect(BonusSportSimples): class BonusDirect(BonusSportAdditif):
"""Bonus direct: les points sont directement ajoutés à la moyenne générale. """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. Les coefficients sont ignorés: tous les points de bonus sont sommés.
(rappel: la note est ramenée sur 20 avant application). (rappel: la note est ramenée sur 20 avant application).
@ -264,7 +260,7 @@ class BonusStDenis(BonusIUTV):
bonus_moy_gen_limit = 0.5 bonus_moy_gen_limit = 0.5
class BonusColmar(BonusSportSimples): class BonusColmar(BonusSportAdditif):
"""Calcul bonus modules optionels (sport, culture), règle IUT Colmar. """Calcul bonus modules optionels (sport, culture), règle IUT Colmar.
Les étudiants de l'IUT peuvent suivre des enseignements optionnels Les étudiants de l'IUT peuvent suivre des enseignements optionnels
@ -298,11 +294,8 @@ class BonusTours(BonusDirect):
proportion_point = 1.0 / 40.0 proportion_point = 1.0 / 40.0
# ---- Un peu moins simples (mais pas trop compliqué)
# Bonus simple, mais avec changement de paramètres en 2010 ! # Bonus simple, mais avec changement de paramètres en 2010 !
class BonusLille(BonusSportSimples): class BonusLille(BonusSportAdditif):
"""Calcul bonus modules optionels (sport, culture), règle IUT Villeneuve d'Ascq """Calcul bonus modules optionels (sport, culture), règle IUT Villeneuve d'Ascq
Les étudiants de l'IUT peuvent suivre des enseignements optionnels Les étudiants de l'IUT peuvent suivre des enseignements optionnels
@ -328,25 +321,39 @@ class BonusLille(BonusSportSimples):
) )
def bonus_iut1grenoble_2017(notes_sport, coefs, infos=None): class BonusSportMultiplicatif(BonusSport):
"""Calcul bonus sport IUT Grenoble sur la moyenne générale (version 2017) """Bonus sport qui multiplie les moyennes d'UE par un facteur"""
La note de sport de nos étudiants va de 0 à 5 points. seuil_moy_gen = 10.0 # seuls les points au dessus du seuil sont comptés
Chaque point correspond à un % qui augmente la moyenne de chaque UE et la moyenne générale. amplitude = 0.005 # multiplie les points au dessus du seuil
Par exemple : note de sport 2/5 : la moyenne générale sera augmentée de 2%.
Calcul ici du bonus sur moyenne générale # C'est un bonus "multiplicatif": on l'exprime en additif,
""" # sur chaque moyenne d'UE m_0
# les coefs sont ignorés # Augmenter de 5% correspond à multiplier par a=1.05
# notes de 0 à 5/20 # m_1 = a . m_0
points = sum([x for x in notes_sport]) # m_1 = m_0 + bonus
factor = (points / 4.0) / 100.0 # bonus = m_0 (a - 1)
bonus = infos["moy"] * factor def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan):
"""calcul du bonus"""
# 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)
return bonus factor = (notes - self.seuil_moy_gen) * self.amplitude # 5% si note=20
factor[factor <= 0] = 0.0 # note < seuil_moy_gen, pas de bonus
# S'applique qu'aux moyennes d'UE
bonus = self.etud_moy_ue * factor
self.bonus_ues = bonus # DataFrame
if not self.formsemestre.formation.is_apc():
# s'applique à la moyenne générale
self.bonus_moy_gen = bonus
class BonusGrenobleIUT1(BonusSport): class BonusGrenobleIUT1(BonusSportMultiplicatif):
"""Bonus IUT1 de Grenoble """Bonus IUT1 de Grenoble
À compter de sept. 2021: À compter de sept. 2021:
@ -372,27 +379,63 @@ class BonusGrenobleIUT1(BonusSport):
# m_1 = m_0 + bonus # m_1 = m_0 + bonus
# bonus = m_0 (a - 1) # bonus = m_0 (a - 1)
def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan):
"""calcul du bonus""" """calcul du bonus, avec réglage différent suivant la date"""
# 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)
if self.formsemestre.date_debut > datetime.date(2021, 7, 15): if self.formsemestre.date_debut > datetime.date(2021, 7, 15):
factor = (notes - 10.0) * 0.005 # 5% si note=20 self.seuil_moy_gen = 10.0
factor[factor <= 0] = 0.0 # note < 10, pas de bonus self.amplitude = 0.005
else: # anciens semestres else: # anciens semestres
factor = notes / 400.0 self.seuil_moy_gen = 0.0
factor[factor <= 0] = 0.0 # facteur 1 si bonus nul self.amplitude = 1 / 400.0
# S'applique qu'aux moyennes d'UE super().compute_bonus(sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan)
bonus = self.etud_moy_ue * factor
self.bonus_ues = bonus # DataFrame
if not self.formsemestre.formation.is_apc():
# s'applique à la moyenne générale class BonusLeHavre(BonusSportMultiplicatif):
self.bonus_moy_gen = bonus """Bonus sport IUT du Havre sur moyenne générale et UE
Les points des modules bonus au dessus de 10/20 sont ajoutés,
et les moyennes d'UE augmentées de 5% de ces points.
"""
name = "bonus_iutlh"
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
class BonusNantes(BonusSportAdditif):
"""IUT de Nantes (Septembre 2018)
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"
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_moy_gen_limit = 0.5 # plafonnement à 0.5 points
class BonusRoanne(BonusSportAdditif):
"""IUT de Roanne.
Le bonus est compris entre 0 et 0.35 point
et est toujours appliqué aux UEs.
"""
name = "bonus_iutr"
seuil_moy_gen = 0.0
bonus_moy_gen_limit = 0.35 # plafonnement à 0.35 points
apply_bonus_mg_to_ues = True # sur les UE, même en DUT et LP
class BonusVilleAvray(BonusSport): class BonusVilleAvray(BonusSport):