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 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.scodoc import bonus_sport
from app.scodoc.sco_codes_parcours import UE_SPORT
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:
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:
seuil_moy_gen = None
proportion_point = None
@ -167,10 +164,9 @@ class BonusSport:
"""Les bonus à appliquer aux UE
Résultat: DataFrame de float, index etudid, columns: ue.id
"""
if (
self.formsemestre.formation.is_apc()
and self.apc_apply_bonus_mg_to_ues
and self.bonus_ues is None
if self.bonus_ues is None and (
(self.apc_apply_bonus_mg_to_ues and self.formsemestre.formation.is_apc())
or self.apply_bonus_mg_to_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)
@ -189,10 +185,10 @@ class BonusSport:
return self.bonus_moy_gen
class BonusSportSimples(BonusSport):
"""Les 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),
soit réparti sur les UE (formations APC).
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
@ -231,7 +227,7 @@ class BonusSportSimples(BonusSport):
# 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
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
class BonusDirect(BonusSportSimples):
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).
@ -264,7 +260,7 @@ class BonusStDenis(BonusIUTV):
bonus_moy_gen_limit = 0.5
class BonusColmar(BonusSportSimples):
class BonusColmar(BonusSportAdditif):
"""Calcul bonus modules optionels (sport, culture), règle IUT Colmar.
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
@ -298,11 +294,8 @@ class BonusTours(BonusDirect):
proportion_point = 1.0 / 40.0
# ---- Un peu moins simples (mais pas trop compliqué)
# 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
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):
"""Calcul bonus sport IUT Grenoble sur la moyenne générale (version 2017)
class BonusSportMultiplicatif(BonusSport):
"""Bonus sport qui multiplie les moyennes d'UE par un facteur"""
La note de sport de nos étudiants va de 0 à 5 points.
Chaque point correspond à un % qui augmente la moyenne de chaque UE et la moyenne générale.
Par exemple : note de sport 2/5 : la moyenne générale sera augmentée de 2%.
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
Calcul ici du bonus sur moyenne générale
"""
# les coefs sont ignorés
# notes de 0 à 5/20
points = sum([x for x in notes_sport])
factor = (points / 4.0) / 100.0
bonus = infos["moy"] * factor
# 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"""
# 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
À compter de sept. 2021:
@ -372,27 +379,63 @@ class BonusGrenobleIUT1(BonusSport):
# 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"""
# 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)
"""calcul du bonus, avec réglage différent suivant la date"""
if self.formsemestre.date_debut > datetime.date(2021, 7, 15):
factor = (notes - 10.0) * 0.005 # 5% si note=20
factor[factor <= 0] = 0.0 # note < 10, pas de bonus
self.seuil_moy_gen = 10.0
self.amplitude = 0.005
else: # anciens semestres
factor = notes / 400.0
factor[factor <= 0] = 0.0 # facteur 1 si bonus nul
self.seuil_moy_gen = 0.0
self.amplitude = 1 / 400.0
# S'applique qu'aux moyennes d'UE
bonus = self.etud_moy_ue * factor
self.bonus_ues = bonus # DataFrame
super().compute_bonus(sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan)
if not self.formsemestre.formation.is_apc():
# s'applique à la moyenne générale
self.bonus_moy_gen = bonus
class BonusLeHavre(BonusSportMultiplicatif):
"""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):