"""
----------------------------------------------------------------- model_run.py
ANUGA MODELLING TEMPLATE (Model evolution (simulation))
Script for running (evolving) the model simulation. (Parallel processor version)

Model data for the run is read in and pre-processed in model_data.py, This data
is then used in model_build.py to create the model mesh and domain before
running (evolving) the simulation in this script. Initialisation variables are
set in model_ini.py and read in when this script is initiated.

<<<<< THIS SCRIPT  IS THE  MAINLINE SCRIPT  IMPORTING ALL OTHERS >>>>>
<<<<< It is typically executed by CDing to the scripts directory >>>>>
<<<<< and executing 'mpirun -npxx python model_run.py' in a      >>>>>
<<<<< command window . Note this MPI version only runs under     >>>>>
<<<<< Ubuntu - Windows only runs in single CPU mode. It will be  >>>>>
<<<<< necessary to edit these scripts to remove the various MPI  >>>>>
<<<<< commands before running on Windows.                        >>>>>

Version     : 2.00 August 2015 flood template modified for tsunami modelling
            : 2.01 December 2015 scrip[ts converted to use MPI on Ubuntu
Author      : E Rigby (0437 250 500) ted.rigby@rienco.com.au

-------------------------------------------------------------------------------
"""

#------------------------------------------------------------------------------
# Import necessary modules
#------------------------------------------------------------------------------

# Standard python modules
import os
import sys
import time

# ANUGA modules
import anuga


# Simulation specific imports
import model_ini        # Assigns the model specific variables, flages and files
import model_data       # Reads in and processes the scenario-event specific data
import model_build      # Constructs the model mesh/domain and assign BC

# Import the tools to manage the parallel interface
from anuga import distribute, myid, numprocs, finalize, barrier


#################################################################################
#                                                                               #
#                            RUN THE SIMULATION                                 #
#                                                                               #
#################################################################################


#--------------------------------------------------------------------------------
# This section starts the analysis of flow through the domain from the specified
# (model) starttime  for to the specified (model) duration also called finaltime
# All internal model time is in seconds.
#
#***** Note finaltime is currently coded  in Anuga as duration (bug!!)
#***** Best to use the alternative 'duration =' as this is actually what applies
#
# Note:
# 1. -- The internal computational timestep is set at each timestep to meet a CFL=1
#       limit. It is therefore important to examine the mesh statistics to see that
#       there are no unintended small or poorly shaped triangles, particularly in
#       areas of deeper water as they can dramatically reduce the computational
#       timerstep and slow the model down.
# 2. -- The model runs on 'internal' time which will normally differ from model
#       or 'Design' event time as input by the user in various datafiles. This
#       'internal'time is normally not seen by the user but users should be aware
#       of its existence. Both are printed out by this script.
# 3. -- In a similar fashion the model runs with all coordinates recomputed to a
#       local lower left frame origin (to impove numerical precission). The output
#       files are in these 'internal' coordinates but each file also stores the new
#       origin coordintes from which the model coordinates can be restored
#       (as presently occurs in the Anuga viewer and other post processors)
#
#---------------------------------------------------------------------------------

# Start execution of the actual simulation for the as built model

# Resync processors
barrier()

if myid == 0:
    print model_ini.prefix+' >>>> Starting the simulation for ',model_ini.prefix
    print model_ini.prefix+' >>>> Comencing model_run.py code execution at t= %.2f hours'  %(float(time.time()-model_ini.t0)/3600.0)
    print model_ini.prefix+' >>>> Simulation runs for %.2f hours starting at %.2f hours with output to the sww file at %.0f minute intervals ' \
                               %( model_ini.duration/3600.0, model_ini.starttime/3600.0,  float(model_ini.yieldstep/60.0))

# Resync processors, bring in the partitioned domain and set run parameters
barrier()
domain = model_build.domain  # bring in the parallel domain built in model_build

if model_ini.dune_erosion :

    # reassign base elevations to partitioned domains on all proc so can use in operators
    nsbase_elev_c = domain.get_quantity('nsbase_elevation').get_values(location='centroids')

    if myid  == 0:
        print model_ini.prefix+' >>>> Dune erosion  is included in this simulation '

        for i in range(7) :     # 12 erosion zones in this current scenario (--- need to generalise better ER?????????????
            print model_ini.prefix+' >>>> Seting up the dune erosion  operator(s) for erosion zone ', model_data.erosion_polygons[i][2]
            if model_ini.model_verbose :
                print model_ini.prefix+' ----- Zone coords for', model_data.erosion_polygons[i][2] , model_data.erosion_polygons[i][0]
    if model_ini.model_verbose :
        print model_ini.prefix+' ----- nsbase on processor ', myid , 'is of length ',len(nsbase_elev_c)

    from sanddune_erosion_operator import sanddune_erosion_operator # import the erosion operator

    # setup the calls to the erosion operator - one for each zone - note domain is now the partitioned domain (need to generalise this better ER??????)
    # op0
    op0 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[0][0], verbose=model_ini.model_verbose)
    # op1
    op1 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[1][0], verbose=model_ini.model_verbose)
    # op2
    op2 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[2][0], verbose=model_ini.model_verbose)
    # op3
    op3 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[3][0], verbose=model_ini.model_verbose)
    # op4
    op4 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[4][0], verbose=model_ini.model_verbose)
    # op5
    op5 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[5][0], verbose=model_ini.model_verbose)
    # op6
    op6 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[6][0], verbose=model_ini.model_verbose)
    # op7
##    op7 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[7][0], verbose=model_ini.model_verbose)
##    # op8
##    op8 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[8][0], verbose=model_ini.model_verbose)
##    # op9
##    op9 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[9][0], verbose=model_ini.model_verbose)
##    # op10
##    op10 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[10][0], verbose=model_ini.model_verbose)
##    # op11
##    op11 = sanddune_erosion_operator(domain, base=nsbase_elev_c, polygon=model_data.erosion_polygons[11][0], verbose=model_ini.model_verbose)

#------------------------------------------------------------------------------
# Evolve  simulation through time
#------------------------------------------------------------------------------

barrier()

# Run the simulation in the paralel domain
for t in domain.evolve(yieldstep = model_ini.yieldstep, duration = model_ini.duration):     # This is a steptime loop (not computaional timestep loop)
    # For this yieldstep confirm where we are at
    barrier()
    if myid == 0:
        print model_ini.prefix+' >>>> Evolve is at a timestep with internal time of %.0f secs and model time of %.0f secs' %( t,domain.starttime+t  )



# Parallel run completed - tidy up
barrier()
if myid == 0:
    print model_ini.prefix+' >>>> Simulation completed succesfully for ', model_ini.prefix
    print model_ini.prefix+' >>>> Completed ', model_ini.duration/3600.0, ' hours of model simulation at t= %.2f hours' %(float(time.time()-model_ini.t0)/3600.0)
    print model_ini.prefix+' >>>> Merging the individual cpu sww files and deleting the individual swws once merged'

# Merge the individual parallel swws created by the n processors
barrier()                         # wait foir all processors to complete
domain.sww_merge(delete_old=True)

if myid == 0:
    print model_ini.prefix+' >>>> Finalising the run -- all done'

# Finaise the parallel code and this model run
barrier()                         # wait for all processors to complete
finalize()


