using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using WebApplication3.Models; using WebApplication3.Clases; using System.IO; using System.IO.Compression; using System.Threading; using Newtonsoft.Json; namespace WebApplication3.Controllers { [Route("api/[controller]")] [ApiController] public class SimulacionController : ControllerBase { private readonly AquiferContext _context; private PozoController pozoController; private RecargasController recargasController; private AcuiferoController acuiferoController; private ServicioController serviceController; private BalanceHidricoController balanceHidricoController; private PiezometriaController piezometriaController; private ServiceQueueController serviceQueueController; public SimulacionController(AquiferContext context) { _context = context; pozoController = new PozoController(context); recargasController = new RecargasController(context); acuiferoController = new AcuiferoController(context); serviceController = new ServicioController(context); balanceHidricoController = new BalanceHidricoController(context); piezometriaController= new PiezometriaController(context); serviceQueueController = new ServiceQueueController(context); } // GET: api/Simulacion [HttpGet] public async Task>> GetSimulaciones() { return await _context.Simulaciones.ToListAsync(); } // GET: api/Simulacion/5 [HttpGet("{id}")] public async Task> GetSimulacion(uint id) { var simulacion = await _context.Simulaciones.FindAsync(id); if (simulacion == null) { return NotFound(); } return simulacion; } // POST: api/Simulacion // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 [HttpPost] public async Task> PostSimulacion(Simulacion simulacion) { _context.Simulaciones.Add(simulacion); await _context.SaveChangesAsync(); //prepacion de los valores por defecto para la simulación pozoController.SetPozosSimulacion(simulacion.IdAcuifero,simulacion.Id); recargasController.SetRecargasSimulacion(simulacion.IdAcuifero, simulacion.Id); return CreatedAtAction("GetSimulacion", new { id = simulacion.Id }, simulacion); } [HttpPost("Simula/{simulacionId}")] public async Task QueueSim(uint simulacionId) { Simulacion simulacion = _context.Simulaciones.Find(simulacionId); ServiceQueue serviceQueue = new ServiceQueue(); serviceQueue.IdSimulacion = simulacionId; serviceQueue.IdAcuifero = simulacion.IdAcuifero; await serviceQueueController.PostServiceQueue(serviceQueue); return true; } [HttpPut("UpdateSimWellData")] public async Task> UpdateSimWellsFromCsv(uint simulationId, [FromBody] DatosPostSimulacion data) { bool result = true; Parser parser = new(); Simulacion sim = _context.Simulaciones.Find(simulationId); string file = Constants.PathExtract + data.Fichero.Nombre; //1. Se eliminan los pozos con sus respectivas time series de la bbdd ya que se va a sobreescribir la informacion await pozoController.DeletePozoFromSim(simulationId); //2. Guardamos el fichero que nos viene en el body en formato base64 try { byte[] tempBytes = Convert.FromBase64String(data.Fichero.Base64); System.IO.File.WriteAllBytes( file, tempBytes); } catch (Exception ex) { return Problem(ex.Message); } WellData[] wellDatas = parser.parseWellCSV(file); await pozoController.PostMultipleWells((uint)sim.IdAcuifero,wellDatas); return result; } [HttpPut] public async Task> UpdateSimRechargesFromCsv(uint simulationId, [FromBody] DatosPostSimulacion data) { bool result = true; Parser parser = new(); Simulacion sim = _context.Simulaciones.Find(simulationId); string file = Constants.PathExtract + data.Fichero.Nombre; //1. Se eliminan los pozos con sus respectivas time series de la bbdd ya que se va a sobreescribir la informacion await pozoController.DeletePozoFromSim(simulationId); //2. Guardamos el fichero que nos viene en el body en formato base64 try { byte[] tempBytes = Convert.FromBase64String(data.Fichero.Base64); System.IO.File.WriteAllBytes(file, tempBytes); } catch (Exception ex) { return Problem(ex.Message); } RechargeData[] rechargeDatas = parser.parseRechargeCSV(file); await recargasController.PostMultipleRecharges((uint)sim.IdAcuifero, rechargeDatas); return result; } // PUT: api/Simulacion/5 // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754s [HttpPut("{id}")] public async Task PutSimulacion(uint id, [FromBody] DatosPostSimulacion datos) { Simulacion simulacion = _context.Simulaciones.Find(id); if (id != simulacion.Id) { return BadRequest(); } simulacion.Nombre = (datos.Nombre != null && datos.Nombre != simulacion.Nombre) ? datos.Nombre : simulacion.Nombre; _context.Entry(simulacion).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!SimulacionExists(id)) { return NotFound(); } else { throw; } } return CreatedAtAction("GetSimulacion", new { id = simulacion.Id }, simulacion); } // DELETE: api/Simulacion/5 [HttpDelete("{id}")] public async Task DeleteSimulacion(uint id) { var simulacion = await _context.Simulaciones.FindAsync(id); if (simulacion == null) { return NotFound(); } _context.Simulaciones.Remove(simulacion); await _context.SaveChangesAsync(); return NoContent(); } [NonAction] public async Task SimulaAsync(ServiceQueue serviceQueue) { Logger logger = Logger.GetInstance(); await serviceQueueController.SetCorriendo(serviceQueue.Id); uint simulacionId = (uint)serviceQueue.IdSimulacion; Simulacion simulacion = _context.Simulaciones.Find(simulacionId); //Obtenemos el nombre de fichero original del acuifero string zip = acuiferoController.GetFicheroZip((uint)simulacion.IdAcuifero); Logger.WriteLog("estoy simulando"); if (zip != string.Empty) { Parser parser = new Parser(); string zip_name = "simulaicion" + simulacion.Nombre; string zip_copy = zip_name + ".zip"; System.IO.File.Copy(Constants.PathZip + zip, Constants.PathZip + zip_copy, true); string workingDirectory = Constants.PathExtract + zip_name + "\\"; //Descomprimimos copia para escribir en fichero Directory.CreateDirectory(workingDirectory); ZipFile.ExtractToDirectory(Constants.PathZip + zip_copy, workingDirectory, true); //Obtenemos fichero de pozo y recargas List files = Directory.GetFiles(workingDirectory).ToList(); string pozoFile = files.Find(x => x.Contains(".VMW")); string recargaFile = files.Find(x => x.Contains(".VMP")); string inFile = files.Find(x => x.Contains(".MODFLOW.IN") || x.Contains(".modflow.in")); string zoneFile = files.Find(x => x.Contains(".ZBI") || x.Contains(".zbi")); //3- Parseamos pozos if (System.IO.File.Exists(pozoFile)) { List infoPozosFichero = parser.ParseWellData(pozoFile).ToList(); List pozos = pozoController.GetPozosSimulacion(simulacionId); List lines = new List(); //Por ahora asumimos que el fichero tiene la misma cantidad de pozos que en bbdd para esta simulacion string[] maxDefault = infoPozosFichero[0].ZMax.Split(" "); lines.Add(pozos.Count.ToString()); foreach (Pozo p in pozos) { List timeSeriesPozo = pozoController.GetTsPozoFromPozo(p.Id); lines.Add("0"); //Activo o inactivo lines.Add(p.Nombre); lines.Add(p.Latitud.ToString()); lines.Add(p.Longitud.ToString()); lines.Add(p.Minimo.ToString()); maxDefault[0] = p.Maximo.ToString(); string aux = String.Join(' ', maxDefault); lines.Add(aux); //Maximo lines.Add(infoPozosFichero[0].ScreenIntervals.ToString()); //screen intervals lines.Add(infoPozosFichero[0].Top); lines.Add(infoPozosFichero[0].Bot); lines.Add(timeSeriesPozo.Count.ToString()); for (int i = 0; i < timeSeriesPozo.Count - 1; i++) { lines.Add(timeSeriesPozo[i].MarcaTiempo); lines.Add(timeSeriesPozo[i + 1].MarcaTiempo); lines.Add(timeSeriesPozo[i].Valor.ToString() + " " + timeSeriesPozo[i].InfoComplementaria); } } //System.IO.File.WriteAllLines(@"C:\Users\Admin\Desktop\Test.VMW", lines); System.IO.File.WriteAllLines(pozoFile, lines); } //4- Parseamos recargas if (System.IO.File.Exists(recargaFile)) { List recargas = recargasController.GetRecargasSimulacion(simulacionId); string text = System.IO.File.ReadAllText(recargaFile); string[] data = text.Split("\r\n\r\n"); int layers = int.Parse(data[0][0].ToString()); int blankLinePerBlock = layers + 1; int rechargeBlockInex = blankLinePerBlock * 2; List lines = new List(); //Hasta el bloque de recargas vamos poniendo el texto que le precede for (int i = 0; i < rechargeBlockInex; i++) { lines.AddRange(data[i].Split("\r\n").ToList()); lines.Add(""); } //Bloque recargas lines.Add(recargas.Count.ToString()); int index = 1; foreach (Recarga r in recargas) { List tsRecarga = recargasController.GetTsRecargaFromRecaga(r.Id); lines.Add(index + " 1 Index 1"); lines.Add("1 rchr entries"); lines.Add(index + " " + tsRecarga[0].Valor + " " + tsRecarga[0].MarcaTiempo + " " + tsRecarga[1].MarcaTiempo + " " + tsRecarga[0].InfoComplementaria); } lines.Add(""); //Hasta el final for (int i = rechargeBlockInex + 1; i < data.Length; i++) { lines.AddRange(data[i].Split("\r\n").ToList()); //controlamos que en la ultima iteracion no introduzca un \r\n if (i < data.Length - 1) { lines.Add(""); } } //System.IO.File.WriteAllLines(@"C:\Users\Admin\Desktop\TestRec.VMP", lines); System.IO.File.WriteAllLines(recargaFile, lines); } //5.Ejecutamos el modelo //Primeramente, para ejecutar el modelo, hay que modificar el contenido del fichero con extension .in para que no de error al ejecutarse el modelo if (System.IO.File.Exists(inFile)) { List inFileLines = parser.ParseInFile(inFile); System.IO.File.WriteAllLines(inFile, inFileLines); } string inFileName = inFile.Split("\\").ToList().Last(); Logger.WriteLog("ejecuto modflow"); await serviceController.SimulaModflow(workingDirectory, inFileName); Thread.Sleep(5000); Logger.WriteLog("fin modflow"); //6.Ejecucion Zonebudget //Seguidamente miramos el fichero de resultado de zonas (si existe) if (zoneFile != null && System.IO.File.Exists(zoneFile)) { files = Directory.GetFiles(workingDirectory).ToList(); string budgetFile = files.Find(x => x.Contains(".BGT")); Logger.WriteLog("budgetFile" + budgetFile); await serviceController.SimulaZoneBudget(workingDirectory, budgetFile, zoneFile); Thread.Sleep(5000); Logger.WriteLog("fin zonebudget"); } //7. Parseo de salidas files = Directory.GetFiles(workingDirectory).ToList(); string zoneResultsFile = files.Find(x => x.Contains(".zblst")); string modelResultsFile = files.Find(x => x.Contains(".LST")); string piezometryFile = files.Find(x => x.Contains(".HDS")); //Parseo del fichero de balance hidrico por zonas if (System.IO.File.Exists(zoneResultsFile)) { Logger.WriteLog("inicio balance zonas"); ZoneBalance[] zoneBalance = parser.ParseZonesBalance(zoneResultsFile); //Se inserta el balance hidrico en bbdd foreach (ZoneBalance zone in zoneBalance) { //Obtenemos la respuestas de la creacion con el objeto var resultBalance = await balanceHidricoController.PostBalance(zone.ToBalanceHidrico(simulacionId)); uint balanceId = resultBalance.Value; var dataIn = await balanceHidricoController.PostBalanceIn(zone.In.ToDatosBalanceIn(balanceId)); uint balanceDataInId = dataIn.Value; List conexionZonasIns = new List(); zone.In.ZoneConnections.ForEach(x => conexionZonasIns.Add(x.ToConexionIn(balanceDataInId))); await balanceHidricoController.PostMultipleConnectionIn(conexionZonasIns.ToArray()); var dataOut = await balanceHidricoController.PostBalanceOut(zone.Out.ToDatosBalanceOut(balanceId)); uint balanceDataOutId = dataOut.Value; List conexionZonasOuts = new List(); zone.Out.ZoneConnections.ForEach(x => conexionZonasOuts.Add(x.ToConexionOut(balanceDataOutId))); await balanceHidricoController.PostMultipleConnectionOut(conexionZonasOuts.ToArray()); } Logger.WriteLog("fin balance hidrico zonas"); } //Parseo del fichero de resultados sobre el modelo entero if (System.IO.File.Exists(modelResultsFile)) { Logger.WriteLog("inicio balance modelo entero"); ZoneBalance[] modelBalance = parser.ParseWholeModelBalance(modelResultsFile); //insertamos en bbdd foreach (ZoneBalance zone in modelBalance) { var result = await balanceHidricoController.PostBalance(zone.ToBalanceHidrico(simulacionId)); uint balanceId = result.Value; await balanceHidricoController.PostBalanceIn(zone.In.ToDatosBalanceIn(balanceId)); await balanceHidricoController.PostBalanceOut(zone.Out.ToDatosBalanceOut(balanceId)); } Logger.WriteLog("fin balance modelo entero"); } //Parseo del fichero HDS para obtener el mapa de piezometria if (System.IO.File.Exists(piezometryFile)) { Logger.WriteLog("inicio piezometria"); List piezometrias = parser.ParseBinaryFile(piezometryFile, simulacionId); foreach (Piezometria p in piezometrias) { await piezometriaController.PostPiezometria(p); } Logger.WriteLog("fin piezometria"); } piezometriaController.getDimensions(simulacionId, out int rows, out int cols); await serviceController.GetIsolinesWithPython(workingDirectory, piezometryFile, rows, cols); Thread.Sleep(5000); Byte[] bytes = System.IO.File.ReadAllBytes(workingDirectory + "test.png"); String base64Image = Convert.ToBase64String(bytes); await SetIsolinesImage(simulacionId, base64Image); await serviceQueueController.SetTerminado(serviceQueue.Id); Logger.WriteLog("terminado"); } return true; } [HttpGet("Geojson")] public GeoJson GetGeoJson() { string allText = System.IO.File.ReadAllText(@"C:\Users\Admin\Desktop\AAAA\test_aa.geojson"); allText = allText.Replace("[[[","[["); allText = allText.Replace("]]]", "]]"); GeoJson jsonObject = JsonConvert.DeserializeObject(allText); return jsonObject; } private bool SimulacionExists(uint id) { return _context.Simulaciones.Any(e => e.Id == id); } private async Task SetIsolinesImage(uint simulacionId, string imageBase64) { var simulacion = _context.Simulaciones.Find(simulacionId); if (simulacionId != simulacion.Id) { return BadRequest(); } simulacion.IsolineImage = imageBase64; _context.Entry(simulacion).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!SimulacionExists(simulacionId)) { return NotFound(); } else { throw; } } return CreatedAtAction("GetSimulacion", new { id = simulacion.Id }, simulacion); } /* * TEST ENDPOINTS */ [HttpPost("Simula/Python/{simulacionId}")] public async Task SimIsolinesWithPython(uint simulacionId) { string workingDirectory = @"C:\Users\Admin\Desktop\TestExtract\simulaicionsimulacion_test\"; string headFile = @"C:\Users\Admin\Desktop\TestExtract\simulaicionsimulacion_test\EJEMPLO_SOTIEL.HDS"; int rows, cols; piezometriaController.getDimensions(simulacionId, out rows, out cols); await serviceController.GetIsolinesWithPython(workingDirectory, headFile, rows, cols); Thread.Sleep(3000); return true; } [HttpGet("Piezometria")] public async Task>> SimPiezometria() { Logger.WriteLog("inicio piezometria"); Parser parser = new Parser(); string piezometryFile = @"C:\Users\Admin\Desktop\TestExtract\simulaicionsimulacion_test\EJEMPLO_SOTIEL.HDS"; List piezometrias = parser.ParseBinaryFile(piezometryFile, 4); Logger.WriteLog("Fin parseo fichero binario"); Logger.WriteLog("Hay " + piezometrias.Count + " elementos de piezometria"); foreach (Piezometria p in piezometrias) { await piezometriaController.PostPiezometria(p); } Logger.WriteLog("fin piezometria"); return await GetSimulaciones(); } } }