- add login, logout, registration
- various fix
This commit is contained in:
parent
e587a4cea6
commit
0a1bc21035
14
.idea/csv-editor.xml
generated
14
.idea/csv-editor.xml
generated
@ -17,6 +17,20 @@
|
||||
</Attribute>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="/dumpDataPreview">
|
||||
<value>
|
||||
<Attribute>
|
||||
<option name="separator" value="," />
|
||||
</Attribute>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="/textView">
|
||||
<value>
|
||||
<Attribute>
|
||||
<option name="separator" value="," />
|
||||
</Attribute>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
0
src/auth/__init__.py
Normal file
0
src/auth/__init__.py
Normal file
91
src/auth/login.py
Normal file
91
src/auth/login.py
Normal file
@ -0,0 +1,91 @@
|
||||
import dash_bootstrap_components as dbc
|
||||
from dash import html, dcc
|
||||
|
||||
from components.ids import Ids
|
||||
|
||||
def create_login_layout():
|
||||
return dbc.Container([
|
||||
dbc.Row([
|
||||
dbc.Col([
|
||||
html.H2("Login Dashboard Olio d'Oliva", className="text-center mb-4"),
|
||||
dbc.Card([
|
||||
dbc.CardBody([
|
||||
dbc.Input(
|
||||
id=Ids.LOGIN_USERNAME,
|
||||
type="text",
|
||||
placeholder="Username",
|
||||
className="mb-3"
|
||||
),
|
||||
dbc.Input(
|
||||
id=Ids.LOGIN_PASSWORD,
|
||||
type="password",
|
||||
placeholder="Password",
|
||||
className="mb-3"
|
||||
),
|
||||
dbc.Button(
|
||||
"Login",
|
||||
id=Ids.LOGIN_BUTTON,
|
||||
color="primary",
|
||||
className="w-100 mb-3"
|
||||
),
|
||||
html.Div(id=Ids.LOGIN_ERROR),
|
||||
html.Hr(),
|
||||
html.P("Non hai un account?", className="text-center"),
|
||||
dbc.Button(
|
||||
"Registrati",
|
||||
id=Ids.SHOW_REGISTER_BUTTON,
|
||||
color="secondary",
|
||||
className="w-100"
|
||||
)
|
||||
])
|
||||
])
|
||||
], md=6, className="mx-auto")
|
||||
], className="vh-100 align-items-center")
|
||||
])
|
||||
|
||||
def create_register_layout():
|
||||
return dbc.Container([
|
||||
dbc.Row([
|
||||
dbc.Col([
|
||||
html.H2("Registrazione", className="text-center mb-4"),
|
||||
dbc.Card([
|
||||
dbc.CardBody([
|
||||
dbc.Input(
|
||||
id=Ids.REGISTER_USERNAME,
|
||||
type="text",
|
||||
placeholder="Username",
|
||||
className="mb-3"
|
||||
),
|
||||
dbc.Input(
|
||||
id=Ids.REGISTER_PASSWORD,
|
||||
type="password",
|
||||
placeholder="Password",
|
||||
className="mb-3"
|
||||
),
|
||||
dbc.Input(
|
||||
id=Ids.REGISTER_CONFIRM,
|
||||
type="password",
|
||||
placeholder="Conferma Password",
|
||||
className="mb-3"
|
||||
),
|
||||
dbc.Button(
|
||||
"Registrati",
|
||||
id=Ids.REGISTER_BUTTON,
|
||||
color="primary",
|
||||
className="w-100 mb-3"
|
||||
),
|
||||
html.Div(id=Ids.REGISTER_ERROR),
|
||||
html.Div(id=Ids.REGISTER_SUCCESS),
|
||||
html.Hr(),
|
||||
html.P("Hai già un account?", className="text-center"),
|
||||
dbc.Button(
|
||||
"Torna al Login",
|
||||
id=Ids.SHOW_LOGIN_BUTTON,
|
||||
color="secondary",
|
||||
className="w-100"
|
||||
)
|
||||
])
|
||||
])
|
||||
], md=6, className="mx-auto")
|
||||
], className="vh-100 align-items-center")
|
||||
])
|
||||
236
src/auth/utils.py
Normal file
236
src/auth/utils.py
Normal file
@ -0,0 +1,236 @@
|
||||
import json
|
||||
import os
|
||||
import hashlib
|
||||
import jwt as pyjwt
|
||||
from datetime import datetime, timedelta
|
||||
import secrets
|
||||
|
||||
# Costanti
|
||||
SECRET_KEY = 'M!3EmyJ@P$yqt$dYRQ#73QtxFy$aTn8M98P8i5T9x9Fd5LHMcHgdfEEt#?H9EPg&9Qhokh$#pTyYLHxL' # In produzione, usare una variabile d'ambiente
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
USERS_FILE = os.path.join(BASE_DIR, "users", "users.json")
|
||||
CONFIGS_DIR = os.path.join(BASE_DIR, "users", "configs")
|
||||
|
||||
def init_directory_structure():
|
||||
"""
|
||||
Inizializza la struttura delle directory necessarie per l'applicazione
|
||||
"""
|
||||
# Crea directory per utenti e configurazioni
|
||||
os.makedirs(os.path.dirname(USERS_FILE), exist_ok=True)
|
||||
os.makedirs(CONFIGS_DIR, exist_ok=True)
|
||||
|
||||
# Se il file users.json non esiste, crealo vuoto
|
||||
if not os.path.exists(USERS_FILE):
|
||||
with open(USERS_FILE, 'w') as f:
|
||||
json.dump({}, f)
|
||||
|
||||
print(f"Initialized directory structure:")
|
||||
print(f"Users file: {USERS_FILE}")
|
||||
print(f"Configs directory: {CONFIGS_DIR}")
|
||||
|
||||
def hash_password(password):
|
||||
"""Hash la password usando SHA-256"""
|
||||
return hashlib.sha256(password.encode()).hexdigest()
|
||||
|
||||
# In auth/utils.py
|
||||
def create_user(username, password):
|
||||
"""
|
||||
Crea un nuovo utente
|
||||
Args:
|
||||
username: nome utente
|
||||
password: password in chiaro
|
||||
Returns:
|
||||
tuple: (success: bool, message: str)
|
||||
"""
|
||||
try:
|
||||
print(f"Tentativo di creazione utente: {username}")
|
||||
|
||||
# Inizializza la struttura delle directory
|
||||
init_directory_structure()
|
||||
|
||||
# Inizializza o carica il dizionario degli utenti
|
||||
users = {}
|
||||
if os.path.exists(USERS_FILE):
|
||||
try:
|
||||
with open(USERS_FILE, 'r') as f:
|
||||
content = f.read()
|
||||
if content.strip(): # Verifica che il file non sia vuoto
|
||||
users = json.loads(content)
|
||||
print(f"Utenti esistenti: {len(users)}")
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Errore nel parsing del file utenti: {e}")
|
||||
pass
|
||||
|
||||
# Validazioni
|
||||
if not username or len(username) < 3:
|
||||
return False, "Username deve essere almeno 3 caratteri"
|
||||
if not password or len(password) < 6:
|
||||
return False, "Password deve essere almeno 6 caratteri"
|
||||
if username in users:
|
||||
return False, "Username già esistente"
|
||||
|
||||
# Genera il salt e hash della password
|
||||
salt = secrets.token_hex(8)
|
||||
password_hash = hashlib.sha256((password + salt).encode()).hexdigest()
|
||||
|
||||
# Ottieni il percorso della configurazione utente
|
||||
user_config = get_user_config_path(username)
|
||||
print(f"Percorso configurazione utente: {user_config}")
|
||||
|
||||
# Crea la configurazione dell'utente
|
||||
os.makedirs(os.path.dirname(user_config), exist_ok=True)
|
||||
|
||||
# Salva la configurazione di default
|
||||
default_config = get_default_config()
|
||||
with open(user_config, 'w') as f:
|
||||
json.dump(default_config, f, indent=4)
|
||||
print("Configurazione default salvata")
|
||||
|
||||
# Aggiungi nuovo utente con struttura semplificata
|
||||
users[username] = {
|
||||
"salt": salt,
|
||||
"password_hash": password_hash
|
||||
}
|
||||
|
||||
# Salva il file utenti
|
||||
with open(USERS_FILE, 'w') as f:
|
||||
json.dump(users, f, indent=4)
|
||||
print("File utenti aggiornato con successo")
|
||||
|
||||
return True, "Utente creato con successo"
|
||||
|
||||
except Exception as e:
|
||||
print(f"Errore nella creazione dell'utente: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False, f"Errore nella creazione dell'utente: {str(e)}"
|
||||
|
||||
def verify_user(username, password):
|
||||
"""
|
||||
Verifica le credenziali utente usando salt e hash
|
||||
Args:
|
||||
username: nome utente
|
||||
password: password in chiaro
|
||||
Returns:
|
||||
bool: True se le credenziali sono valide, False altrimenti
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists(USERS_FILE):
|
||||
print("File utenti non trovato")
|
||||
return False
|
||||
|
||||
with open(USERS_FILE, 'r') as f:
|
||||
users = json.load(f)
|
||||
|
||||
if username not in users:
|
||||
print("Username non trovato")
|
||||
return False
|
||||
|
||||
# Ottieni il salt e l'hash salvati
|
||||
user_data = users[username]
|
||||
stored_salt = user_data['salt']
|
||||
stored_hash = user_data['password_hash']
|
||||
|
||||
# Calcola l'hash della password fornita con il salt salvato
|
||||
password_hash = hashlib.sha256((password + stored_salt).encode()).hexdigest()
|
||||
|
||||
# Confronta gli hash
|
||||
return stored_hash == password_hash
|
||||
|
||||
except Exception as e:
|
||||
print(f"Errore nella verifica dell'utente: {str(e)}")
|
||||
return False
|
||||
|
||||
def create_token(username):
|
||||
"""Crea JWT token"""
|
||||
expiration = datetime.utcnow() + timedelta(hours=24)
|
||||
return pyjwt.encode(
|
||||
{"user": username, "exp": expiration},
|
||||
SECRET_KEY,
|
||||
algorithm="HS256"
|
||||
)
|
||||
|
||||
def verify_token(token):
|
||||
"""Verifica JWT token"""
|
||||
try:
|
||||
payload = pyjwt.decode(token, SECRET_KEY, algorithms=["HS256"])
|
||||
return True, payload["user"]
|
||||
except pyjwt.ExpiredSignatureError:
|
||||
return False, "Token scaduto"
|
||||
except pyjwt.InvalidTokenError:
|
||||
return False, "Token non valido"
|
||||
|
||||
def get_user_config_path(username):
|
||||
"""
|
||||
Restituisce il percorso del file di configurazione per l'utente specificato
|
||||
Args:
|
||||
username: nome utente
|
||||
Returns:
|
||||
str: percorso assoluto del file di configurazione
|
||||
"""
|
||||
# Sostituisci caratteri non validi nel nome utente
|
||||
safe_username = "".join(c for c in username if c.isalnum() or c in ('-', '_'))
|
||||
|
||||
# Costruisci il percorso assoluto
|
||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
config_dir = os.path.join(base_dir, 'config', 'users')
|
||||
config_path = os.path.join(config_dir, f"{safe_username}_config.json")
|
||||
|
||||
# Assicurati che la directory esista
|
||||
os.makedirs(os.path.dirname(config_path), exist_ok=True)
|
||||
|
||||
return config_path
|
||||
|
||||
def get_default_config():
|
||||
return {
|
||||
"oliveto": {
|
||||
"hectares": 1,
|
||||
"varieties": [
|
||||
{
|
||||
"variety": "Nocellara dell'Etna",
|
||||
"technique": "tradizionale",
|
||||
"percentage": 50
|
||||
},
|
||||
{
|
||||
"variety": "Frantoio",
|
||||
"technique": "tradizionale",
|
||||
"percentage": 10
|
||||
},
|
||||
{
|
||||
"variety": "Coratina",
|
||||
"technique": "tradizionale",
|
||||
"percentage": 40
|
||||
}
|
||||
]
|
||||
},
|
||||
"costs": {
|
||||
"fixed": {
|
||||
"ammortamento": 2000,
|
||||
"assicurazione": 500,
|
||||
"manutenzione": 800,
|
||||
"certificazioni": 3000
|
||||
},
|
||||
"variable": {
|
||||
"raccolta": 0.35,
|
||||
"potatura": 600,
|
||||
"fertilizzanti": 400,
|
||||
"irrigazione": 300
|
||||
},
|
||||
"transformation": {
|
||||
"molitura": 0.15,
|
||||
"stoccaggio": 0.2,
|
||||
"bottiglia": 1.2,
|
||||
"etichettatura": 0.3
|
||||
},
|
||||
"marketing": {
|
||||
"budget_annuale": 15000,
|
||||
"costi_commerciali": 0.5,
|
||||
"prezzo_vendita": 12,
|
||||
"perc_vendita_diretta": 30
|
||||
}
|
||||
},
|
||||
"inference": {
|
||||
"debug_mode": True,
|
||||
'model_path': './sources/olive_oil_transformer/olive_oil_transformer_model.keras'
|
||||
}
|
||||
}
|
||||
104
src/components/ids.py
Normal file
104
src/components/ids.py
Normal file
@ -0,0 +1,104 @@
|
||||
# components/ids.py
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class Ids:
|
||||
# Auth Container
|
||||
AUTH_CONTAINER = 'auth-container'
|
||||
DASHBOARD_CONTAINER = 'dashboard-container'
|
||||
|
||||
# Login Form
|
||||
LOGIN_FORM = 'login-form'
|
||||
LOGIN_USERNAME = 'login-username'
|
||||
LOGIN_PASSWORD = 'login-password'
|
||||
LOGIN_BUTTON = 'login-button'
|
||||
LOGIN_ERROR = 'login-error'
|
||||
|
||||
# Register Form
|
||||
REGISTER_FORM = 'register-form'
|
||||
REGISTER_USERNAME = 'register-username'
|
||||
REGISTER_PASSWORD = 'register-password'
|
||||
REGISTER_CONFIRM = 'register-confirm'
|
||||
REGISTER_BUTTON = 'register-button'
|
||||
REGISTER_ERROR = 'register-error'
|
||||
REGISTER_SUCCESS = 'register-success'
|
||||
|
||||
# Navigation
|
||||
SHOW_REGISTER_BUTTON = 'show-register-button'
|
||||
SHOW_LOGIN_BUTTON = 'show-login-button'
|
||||
|
||||
# Inference
|
||||
INFERENCE_CONTAINER = 'inference-container'
|
||||
INFERENCE_STATUS = 'inference-status'
|
||||
INFERENCE_MODE = 'inference-mode'
|
||||
INFERENCE_LATENCY = 'inference-latency'
|
||||
INFERENCE_REQUESTS = 'inference-requests'
|
||||
INFERENCE_COUNTER = 'inference-counter'
|
||||
DEBUG_SWITCH = 'debug-switch'
|
||||
|
||||
# Simulation
|
||||
SIMULATE_BUTTON = 'simulate-btn'
|
||||
GROWTH_CHART = 'growth-simulation-chart'
|
||||
PRODUCTION_CHART = 'production-simulation-chart'
|
||||
SIMULATION_SUMMARY = 'simulation-summary'
|
||||
KPI_CONTAINER = 'kpi-container'
|
||||
PRODUCTION_DEBUG_SWITCH = 'production-debug-switch'
|
||||
PRODUCTION_INFERENCE_REQUESTS = 'production-inference-requests'
|
||||
PRODUCTION_INFERENCE_MODE = 'production-inference-mode'
|
||||
|
||||
# Environment Controls
|
||||
TEMP_SLIDER = 'temp-slider'
|
||||
HUMIDITY_SLIDER = 'humidity-slider'
|
||||
RAINFALL_INPUT = 'rainfall-input'
|
||||
RADIATION_INPUT = 'radiation-input'
|
||||
|
||||
# Production Views
|
||||
OLIVE_PRODUCTION_HA = 'olive-production_ha'
|
||||
OIL_PRODUCTION_HA = 'oil-production_ha'
|
||||
WATER_NEED_HA = 'water-need_ha'
|
||||
OLIVE_PRODUCTION = 'olive-production'
|
||||
OIL_PRODUCTION = 'oil-production'
|
||||
WATER_NEED = 'water-need'
|
||||
PRODUCTION_DETAILS = 'production-details'
|
||||
WEATHER_IMPACT = 'weather-impact'
|
||||
WATER_NEEDS = 'water-needs'
|
||||
EXTRA_INFO = 'extra-info'
|
||||
|
||||
# Configuration
|
||||
HECTARES_INPUT = 'hectares-input'
|
||||
VARIETY_1_DROPDOWN = 'variety-1-dropdown'
|
||||
TECHNIQUE_1_DROPDOWN = 'technique-1-dropdown'
|
||||
PERCENTAGE_1_INPUT = 'percentage-1-input'
|
||||
VARIETY_2_DROPDOWN = 'variety-2-dropdown'
|
||||
TECHNIQUE_2_DROPDOWN = 'technique-2-dropdown'
|
||||
PERCENTAGE_2_INPUT = 'percentage-2-input'
|
||||
VARIETY_3_DROPDOWN = 'variety-3-dropdown'
|
||||
TECHNIQUE_3_DROPDOWN = 'technique-3-dropdown'
|
||||
PERCENTAGE_3_INPUT = 'percentage-3-input'
|
||||
PERCENTAGE_WARNING = 'percentage-warning'
|
||||
|
||||
# Cost Inputs
|
||||
COST_AMMORTAMENTO = 'cost-ammortamento'
|
||||
COST_ASSICURAZIONE = 'cost-assicurazione'
|
||||
COST_MANUTENZIONE = 'cost-manutenzione'
|
||||
COST_CERTIFICAZIONI = 'cost-certificazioni'
|
||||
COST_RACCOLTA = 'cost-raccolta'
|
||||
COST_POTATURA = 'cost-potatura'
|
||||
COST_FERTILIZZANTI = 'cost-fertilizzanti'
|
||||
COST_IRRIGAZIONE = 'cost-irrigazione'
|
||||
COST_MOLITURA = 'cost-molitura'
|
||||
COST_STOCCAGGIO = 'cost-stoccaggio'
|
||||
COST_BOTTIGLIA = 'cost-bottiglia'
|
||||
COST_ETICHETTATURA = 'cost-etichettatura'
|
||||
COST_MARKETING = 'cost-marketing'
|
||||
COST_COMMERCIALI = 'cost-commerciali'
|
||||
PRICE_OLIO = 'price-olio'
|
||||
PERC_VENDITA_DIRETTA = 'perc-vendita-diretta'
|
||||
|
||||
# Other
|
||||
LOADING_ALERT = 'loading-alert'
|
||||
TABS = 'tabs'
|
||||
SAVE_CONFIG_BUTTON = 'save-config-button'
|
||||
SAVE_CONFIG_MESSAGE = 'save-config-message'
|
||||
LOGOUT_BUTTON = 'logout-button'
|
||||
DEV_MODE = 'dev-mode'
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"oliveto": {
|
||||
"hectares": 4.35,
|
||||
"hectares": 1,
|
||||
"varieties": [
|
||||
{
|
||||
"variety": "Nocellara dell'Etna",
|
||||
@ -10,12 +10,12 @@
|
||||
{
|
||||
"variety": "Frantoio",
|
||||
"technique": "tradizionale",
|
||||
"percentage": 10
|
||||
"percentage": 20
|
||||
},
|
||||
{
|
||||
"variety": "Coratina",
|
||||
"technique": "tradizionale",
|
||||
"percentage": 40
|
||||
"percentage": 30
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -46,6 +46,7 @@
|
||||
}
|
||||
},
|
||||
"inference": {
|
||||
"debug_mode": false
|
||||
"debug_mode": false,
|
||||
"model_path": "./sources/olive_oil_transformer/olive_oil_transformer_model.keras"
|
||||
}
|
||||
}
|
||||
65
src/olive_oil_train_dataset/README.MD
Normal file
65
src/olive_oil_train_dataset/README.MD
Normal file
@ -0,0 +1,65 @@
|
||||
# Olive Oil Production Training Dataset Generator
|
||||
|
||||
## Overview
|
||||
This Python script generates a synthetic training dataset for olive oil production simulation. It simulates various factors affecting olive production including weather conditions, olive varieties, cultivation techniques, and geographical zones.
|
||||
|
||||
## Features
|
||||
- Parallel processing for efficient dataset generation
|
||||
- Batch processing to manage memory usage
|
||||
- Configurable simulation parameters
|
||||
- Weather effect calculations
|
||||
- Multiple olive varieties and cultivation techniques support
|
||||
- Zone-based production simulation
|
||||
|
||||
## Prerequisites
|
||||
Required Python packages:
|
||||
- pandas
|
||||
- numpy
|
||||
- psutil
|
||||
- tqdm
|
||||
- concurrent.futures (part of Python standard library)
|
||||
- multiprocessing (part of Python standard library)
|
||||
|
||||
Required input data files:
|
||||
- `./sources/weather_data_solarenergy.parquet`: Weather data including solar energy measurements
|
||||
- `./sources/olive_varieties.parquet`: Olive varieties and their characteristics
|
||||
|
||||
## Usage
|
||||
|
||||
### Command Line Arguments
|
||||
```bash
|
||||
python olive_oil_train_dataset.create_train_dataset [options]
|
||||
```
|
||||
|
||||
Options:
|
||||
- `--random-seed`: Seed for reproducible results (optional)
|
||||
- `--num-simulations`: Total number of simulations to run (default: 100000)
|
||||
- `--num-zones`: Number of zones per simulation (default: same as num-simulations)
|
||||
- `--batch-size`: Size of each simulation batch (default: 10000)
|
||||
- `--output-path`: Output file path (default: './sources/olive_training_dataset.parquet')
|
||||
- `--max-workers`: Number of parallel workers (default: automatically optimized)
|
||||
|
||||
### Example
|
||||
```bash
|
||||
python olive_oil_train_dataset.create_train_dataset --num-simulations 50 --num-zones 10 --batch-size 50 --output-path "./output/olive_dataset.parquet"
|
||||
```
|
||||
|
||||
## Output
|
||||
The script generates a Parquet file containing simulated olive production data with the following key features:
|
||||
- Simulation and zone identifiers
|
||||
- Weather conditions (temperature, precipitation, solar energy)
|
||||
- Production metrics per olive variety
|
||||
- Oil yield calculations
|
||||
- Water requirements
|
||||
- Cultivation techniques
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Simulation Parameters
|
||||
The simulation takes into account:
|
||||
- Temperature effects on production
|
||||
- Water availability and drought resistance
|
||||
- Solar radiation impact
|
||||
- Variety-specific characteristics
|
||||
- Cultivation technique influence
|
||||
- Zone-specific variations
|
||||
@ -133,22 +133,24 @@ def simulate_zone(base_weather, olive_varieties, year, zone, all_varieties, vari
|
||||
variety_info['Fabbisogno Acqua Estate (m³/ettaro)'] +
|
||||
variety_info['Fabbisogno Acqua Autunno (m³/ettaro)'] +
|
||||
variety_info['Fabbisogno Acqua Inverno (m³/ettaro)']
|
||||
) / 4
|
||||
) / 12
|
||||
|
||||
monthly_water_need = zone_weather.apply(
|
||||
lambda row: calculate_water_need(row, base_water_need, variety_info['Temperatura Ottimale']),
|
||||
axis=1
|
||||
)
|
||||
#print(f'Monthly - {variety} - hectares {hectares} - {monthly_water_need}')
|
||||
monthly_water_need *= np.random.uniform(0.95, 1.05, len(monthly_water_need))
|
||||
#print(f'Monthly 2 - {variety} - hectares {hectares} - {monthly_water_need}')
|
||||
annual_variety_water_need = monthly_water_need.sum() * percentage * hectares
|
||||
|
||||
#print(f'Annual Variety - {variety} - hectares {hectares} - {annual_variety_water_need}')
|
||||
# Aggiorna totali annuali
|
||||
annual_production += annual_variety_production
|
||||
annual_min_oil += min_oil_production
|
||||
annual_max_oil += max_oil_production
|
||||
annual_avg_oil += avg_oil_production
|
||||
annual_water_need += annual_variety_water_need
|
||||
|
||||
#print(f'Total Annual {annual_water_need}')
|
||||
# Aggiorna dati varietà
|
||||
clean_variety = clean_column_name(variety)
|
||||
variety_data[clean_variety].update({
|
||||
@ -240,9 +242,9 @@ def simulate_olive_production_parallel(weather_data, olive_varieties, num_simula
|
||||
print(f"Utilizzando {max_workers} workers ottimali basati sulle risorse del sistema")
|
||||
|
||||
# Calcolo numero di batch
|
||||
num_batches = (num_simulations + batch_size - 1) // batch_size
|
||||
num_batches = (num_simulations * num_zones - 1) // batch_size
|
||||
print(f"Elaborazione di {num_simulations} simulazioni con {num_zones} zone in {num_batches} batch")
|
||||
print(f"Totale record attesi: {num_simulations * num_zones:,}")
|
||||
print(f"Totale record attesi: {num_simulations * num_zones}")
|
||||
|
||||
# Lista per contenere tutti i DataFrame dei batch
|
||||
all_batches = []
|
||||
@ -368,11 +370,11 @@ def calculate_production(variety_info, weather, percentage, hectares, seed):
|
||||
variety_info['Fabbisogno Acqua Inverno (m³/ettaro)']
|
||||
) / 4 * percentage * hectares
|
||||
|
||||
water_need = (
|
||||
base_water_need *
|
||||
(1 + max(0, (weather['temp_mean'] - 20) / 50)) *
|
||||
max(0.6, 1 - (weather['precip_sum'] / 1000))
|
||||
)
|
||||
temp_factor = 1 + max(0, (weather["temp_mean"] - 20) / 50)
|
||||
rain_factor = max(0.6, 1 - (weather["precip_sum"] / 1000))
|
||||
water_need = base_water_need * temp_factor * rain_factor
|
||||
|
||||
print(f'temp factor: {temp_factor} rainfall factor: {rain_factor} water_need: {water_need}')
|
||||
|
||||
return {
|
||||
'variety': variety_info['Varietà di Olive'],
|
||||
|
||||
@ -18,4 +18,7 @@ python-dotenv>=0.21.0
|
||||
psutil>=5.9.0
|
||||
|
||||
# File handling
|
||||
dvc>=2.0.0 # Per la gestione dei file sources.dvc
|
||||
dvc>=2.0.0 # Per la gestione dei file sources.dvc
|
||||
|
||||
# Auth
|
||||
PyJWT==2.7.0
|
||||
@ -424,10 +424,20 @@ def calculate_weather_effect(row, optimal_temp):
|
||||
return combined_effect
|
||||
|
||||
def calculate_water_need(weather_data, base_need, optimal_temp):
|
||||
# Calcola il fabbisogno idrico basato su temperatura e precipitazioni
|
||||
temp_factor = 1 + 0.05 * (weather_data['temp_mean'] - optimal_temp) # Aumenta del 5% per ogni grado sopra l'ottimale
|
||||
rain_factor = 1 - 0.001 * weather_data['precip_sum'] # Diminuisce leggermente con l'aumentare delle precipitazioni
|
||||
return base_need * temp_factor * rain_factor
|
||||
# Calcola il fattore temperatura (minimo 80% del fabbisogno)
|
||||
temp_factor = max(0.8, 1 + 0.05 * (weather_data['temp_mean'] - optimal_temp))
|
||||
|
||||
# Calcola il fattore precipitazioni (minimo 50% del fabbisogno)
|
||||
rain_factor = max(0.5, 1 - 0.001 * weather_data['precip_sum'])
|
||||
|
||||
# Calcola il fabbisogno idrico totale
|
||||
water_need = base_need * temp_factor * rain_factor
|
||||
|
||||
# Debug: controlla che il fabbisogno idrico sia positivo
|
||||
assert water_need >= 0, "Il fabbisogno idrico calcolato è negativo!"
|
||||
|
||||
return water_need
|
||||
|
||||
|
||||
def create_technique_mapping(olive_varieties, mapping_path='./sources/technique_mapping.joblib'):
|
||||
# Estrai tutte le tecniche uniche dal dataset e convertile in lowercase
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user