#!/usr/bin/env python3
import os
import subprocess
from pathlib import Path
import time

# Constants
SIM_AMOUNT = 40  # make bigger for more Simulations in smaller steps or lower for opposite effect
MIN_VEL = 0.8  # smallest simulated inflow speed
MAX_VEL = 4.2  # biggest simulated inflow speed
STEP = (MAX_VEL - MIN_VEL) / SIM_AMOUNT  # steps, in which the speed gets faster
MESHES_PATH = './meshes'  # Directory where the Meshes are

meshes = [f for f in os.listdir(MESHES_PATH) if os.path.isfile(os.path.join(MESHES_PATH, f))]  # load all meshes
DONE_MESHES = []  # list of meshes that are already

sim_count = 1  # to count all simulations
base_path = './generated_data/'  # change if the result dir varies from script dir
Path(base_path).mkdir(parents=True, exist_ok=True)

txtfile = '{}/speed.txt'.format(base_path)  # textfile to remember which simulation has which setup
f1 = open(txtfile, 'w+')
f1.write('mesh;simulation;speed\n')
f1.close()


def startVarSim(mesh_num):
    """starts the simulations with varying inflow for the before given mesh"""
    cur_vel = MIN_VEL
    global sim_count
    while cur_vel <= MAX_VEL:
        sim_name = 's_{}'.format(str(sim_count))
        sim_path = '{}/{}'.format(base_path, sim_name)
        Path(sim_path).mkdir(parents=True, exist_ok=True)

        with open(txtfile, 'a') as f:
            f.write('{};{};{}\n'.format(str(mesh_num), sim_name, str(cur_vel)))  # write the current changed context in text file
           
        case = []
        # change the case file for the new simulation, e.g. change the speed and set result directory within generated_data
        with open('case.sif', 'r') as fl:
            for line in fl:
                if 'Velocity 1' in line:
                    case.append(
                        '  Velocity 1 = Variable Coordinate 2; Real MATC "4*{}*tx*(0.41-tx)/0.41^2"\n'.format(
                            str(cur_vel)))
                elif 'Results Directory' in line:
                    case.append('  Results Directory "{}"\n'.format(sim_path))
                else:
                    case.append(line)

        with open('case.sif', 'w') as fl:
            fl.writelines(case)

        #subprocess.run(['./Elmer/bin/ElmerSolver.exe', "case.sif"])  # run this for sequential execution
        subprocess.run(['mpirun', '-np', '16', 'ElmerSolver_mpi', 'case.sif'])   # parallel, if available
        cur_vel += STEP
        sim_count += 1  # the overall count of simulations


def prepareSim():
    """Prepare simulation by loading the next mesh and converting it into a elmer-compatible format"""
    msh = meshes.pop(0)
    DONE_MESHES.append(msh)
    msh_path = '{}/{}'.format(MESHES_PATH, msh)
    #subprocess.run(
    #    ['./Elmer/bin/ElmerGrid.exe', '14', '2', msh_path, '-out', './'])  # run this for sequential execution
    subprocess.run(['ElmerGrid', '14', '2', msh_path, '-out', './', '-partition', '16', '1', '1'])    # for parallel computing
    # 14 --> what type of input file (gmsh mesh file)
    # 2 --> Type of output file (elmer solver compatible)
    # further see https://usermanual.wiki/Document/ElmerGridManual.3367312957/html


def main():
    """creates a new directory for each mesh and starts the simulations"""
    global meshes
    global base_path

    all_mesh = [f for f in os.listdir(MESHES_PATH) if os.path.isfile(os.path.join(MESHES_PATH, f))]
    meshes = [elem for elem in all_mesh if elem not in DONE_MESHES]
    mesh_count = 1
    t_start = time.time()
    
    while len(meshes) != 0:
        prepareSim()
        startVarSim(mesh_count)
        mesh_count += 1

    print(f"DONE in total {time.time() - t_start} || average per simulation {(time.time() - t_start)/(SIM_AMOUNT+1)}")

    with open('{}/timing.txt'.format(base_path), 'w') as log:
        log.write(f"DONE in total {time.time() - t_start} || average per simulation {(time.time() - t_start)/(SIM_AMOUNT+1)}")

if __name__ == '__main__':
    main()
