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 readonly PozoController pozoController; private readonly RecargasController recargasController; private readonly AcuiferoController acuiferoController; private readonly ServicioController serviceController; private readonly BalanceHidricoController balanceHidricoController; private readonly PiezometriaController piezometriaController; private readonly 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}")] [ProducesResponseType(200)] [ProducesResponseType(404)] 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] [ProducesResponseType(201)] 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}")] [ProducesResponseType(200)] public async Task QueueSim(uint simulacionId) { Simulacion simulacion = _context.Simulaciones.Find(simulacionId); ServiceQueue serviceQueue = new (); serviceQueue.IdSimulacion = simulacionId; serviceQueue.IdAcuifero = simulacion.IdAcuifero; await serviceQueueController.PostServiceQueue(serviceQueue); return true; } [HttpPut("{simulationId}/UpdateSimWellData")] [ProducesResponseType(200)] 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, simulationId); return result; } [HttpPut("{simulationId}/UpdateRechargeWellData")] [ProducesResponseType(200)] 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,sim.Id); return result; } // PUT: api/Simulacion/5 [HttpPut("{id}")] [ProducesResponseType(201)] [ProducesResponseType(400)] [ProducesResponseType(404)] 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}")] [ProducesResponseType(209)] 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) { await serviceQueueController.SetCorriendo(serviceQueue.Id); uint simulacionId = (uint)serviceQueue.IdSimulacion; Simulacion simulacion = _context.Simulaciones.Find(simulacionId); Acuifero aquifer = _context.Acuiferos.Find(simulacion.IdAcuifero); //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 (); string zip_name = "simulacion" + 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); workingDirectory += zip.Replace(".zip", "\\"); //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")); Logger.WriteLog("ficheros clave buscados"); //3- Parseamos pozos if (System.IO.File.Exists(pozoFile)) { Logger.WriteLog("vamos con los pozos"); List infoPozosFichero = parser.ParseWellData(pozoFile).ToList(); List pozos = pozoController.GetPozosSimulacion(simulacionId); List lines = new(); //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.X.ToString()); lines.Add(p.Y.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].Bot); lines.Add(infoPozosFichero[0].Top); lines.Add(timeSeriesPozo.Count.ToString()); for (int i = 0; i < timeSeriesPozo.Count; i++) { lines.Add(timeSeriesPozo[i].MarcaTiempo); lines.Add(timeSeriesPozo[i].MarcaTiempoEnd); lines.Add(timeSeriesPozo[i].Valor + " " + timeSeriesPozo[i].InfoComplementaria); } } //System.IO.File.WriteAllLines(@"C:\Users\Admin\Desktop\Test.VMW", lines); System.IO.File.WriteAllLines(pozoFile, lines); Logger.WriteLog("pozos terminados"); } //4- Parseamos recargas if (System.IO.File.Exists(recargaFile)) { Logger.WriteLog("vamos con recargas"); 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(); //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(tsRecarga.Count + " rchr entries"); tsRecarga.ForEach(x => lines.Add(index + " " + x.Valor + " " + x.MarcaTiempo + " " + x.MarcaTiempoEnd + " " + x.InfoComplementaria) ); //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)) { Logger.WriteLog("tratamos el fichero .IN"); 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"); string modelResultsFile = files.Find(x => x.Contains(".LST")); if (parser.ModflowError(modelResultsFile)) { Logger.WriteLog("El fichero LST para la simulacion con id interno "+simulacion.Id+" tiene error"); await serviceQueueController.SetError(serviceQueue.Id); return true; } //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 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(); 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(); 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); Logger.WriteLog("este es el lenght del balance entero " + modelBalance.Length); //insertamos en bbdd try { 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)); } } catch (Exception ex) { Logger.WriteLog(ex.Message); Logger.WriteLog(ex.InnerException.Message); throw; } 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); Logger.WriteLog("ya tengo la imagen de isolineas"); Logger.WriteLog(workingDirectory + Constants.SVGFileName); Byte[] bytes = System.IO.File.ReadAllBytes(workingDirectory + Constants.SVGFileName); String base64Image = Convert.ToBase64String(bytes); Logger.WriteLog("guardo imagen de isolineas"); Logger.WriteLog(base64Image); await SetIsolinesImage(simulacionId, base64Image); Logger.WriteLog("ya esta guardada"); /* * se transforma la imagen vectorial obtenida anteriormente para transformarla en un geojson */ string svgFileOriginal = workingDirectory + Constants.SVGFileName; string svgModifiedFile = workingDirectory + Constants.SVGGeoJson; string geoJsonFile = workingDirectory + Constants.GeoJsonFileName; if (System.IO.File.Exists(svgFileOriginal)) { if (Utilities.ModifySVG(svgFileOriginal, aquifer.WorldOriginX, aquifer.WorldOriginY, aquifer.Length, aquifer.Height, svgModifiedFile)) { await serviceController.GetGeoJsonFromSVG(workingDirectory, svgModifiedFile); if (System.IO.File.Exists(geoJsonFile)) { await SetGeoJson(simulacionId, geoJsonFile); } } } await serviceQueueController.SetTerminado(serviceQueue.Id); Logger.WriteLog("terminado"); try { Directory.Delete(workingDirectory); }catch(Exception ex) { Logger.WriteLog(ex.Message); Logger.WriteLog(ex.InnerException.Message); } } return true; } [HttpGet("Geojson/{id}")] [ProducesResponseType(200)] public async Task GetGeoJson(uint id) { Simulacion s = await _context.Simulaciones.FindAsync(id); GeoJson jsonObject = JsonConvert.DeserializeObject(s.Geojson); return jsonObject; } private bool SimulacionExists(uint id) { return _context.Simulaciones.Any(e => e.Id == id); } private async Task SetGeoJson(uint simulationId, string geojsonFile) { string allText = System.IO.File.ReadAllText(geojsonFile); allText = allText.Replace("[[[","[["); allText = allText.Replace("]]]", "]]"); var simulation = _context.Simulaciones.Find(simulationId); if (simulationId!= simulation.Id) { return BadRequest(); } simulation.Geojson = allText; _context.Entry(simulation).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!SimulacionExists(simulationId)) { return NotFound(); } else { throw; } } return CreatedAtAction("GetSimulacion", new { id = simulation.Id }, simulation); } private async Task SetIsolinesImage(uint simulacionId, string imageBase64) { Simulacion simulacion = _context.Simulaciones.Find(simulacionId); Logger.WriteLog("sim "+simulacion.Id); if (simulacionId != simulacion.Id) { return BadRequest(); } simulacion.IsolineImage = imageBase64; Logger.WriteLog(imageBase64); _context.Entry(simulacion).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (Exception ex) { if (!SimulacionExists(simulacionId)) { return NotFound(); } else { Logger.WriteLog(ex.Message); Logger.WriteLog(ex.InnerException.Message); throw; } } Logger.WriteLog("OKIDOKI ISO SAVED"); return CreatedAtAction("GetSimulacion", new { id = simulacion.Id }, simulacion); } } }