<reponame>leyel/BoSSS<gh_stars>1-10
% !TeX spellcheck = en_GB

\BoSSSopen{MetaJobManager/MetaJobManager}
\graphicspath{{MetaJobManager/MetaJobManager.texbatch/}}

\paragraph{What's new:} 
\begin{itemize}
	\item running multiple simulations in batch mode
	\item deploying and running simulations on a remote machine, e.g. a Microsoft HPC Cluster
	\item access statistics for multiple simulations
\end{itemize}

\paragraph{Prerequisites:} 
\begin{itemize}
	\item basic knowledge of \BoSSSpad{}
	\item executing runs on your local machine, e.g. the quickstart guide of the \ac{cns}, see chapter 5
\end{itemize}

\BoSSS ~includes several tools which aid the advanced user in running simulations and organizing simulation results among multiple computers and/or compute clusters.

%In this tutorial, the following tasks will be illustrated:
%\begin{itemize}
%	\item The use of the meta job manager to run simulations, 
%	on the local machine as well as on a Microsoft HPC cluster
%	\item The evaluation of a simulation using the session table.
%\end{itemize}

The purpose of the meta job manager (a.k.a. the meta job scheduler)
is to provide a universal interface to multiple \emph{job managers} (aka. \emph{batch systems}).
By this interface, the user can run computations on remote and local systems directly from the \BoSSSpad{}.

Furthermore, \BoSSSpad{}  provides a \emph{session table},
which presents various statistics from all \emph{sessions} in the project
(each time a simulation is run, a session is stored in the \BoSSS ~database).

Before you dive into advanced features of \BoSSSpad{}, you should familiarise yourself with the basics of \BoSSS and \BoSSSpad{} and run some first simulations on your local machine, e.g. the tutorials on scalar advection \ref{ScalarAdvection} or Poisson equation \ref{sec:SIP}.

The examples presented in this chapter use the compressible Navier-Stokes solver (CNS), which has been introduced in the previous chapter \ref{CNS}.



 \section{Initialization}
\BoSSScmd{
restart;
 }
\BoSSSexeSilent
\BoSSScmd{
/// The very first thing we have to do is to initialize the workflow
/// management tools and to define a project name. The meta job manager, like  
/// all other workflow management tools strictly enforces the use of a 
/// project name:
WorkflowMgm.Init("MetaJobManager\_Tutorial");
 }
\BoSSSexe
\BoSSScmd{
/// We verify that we have no jobs defined so far
WorkflowMgm.AllJobs;
 }
\BoSSSexe
\BoSSScmdSilent{
/// BoSSScmdSilent BoSSSexeSilent
// first, do some cleanup\newline 
//if(System.IO.Directory.Exists(@"C:\textbackslash tmp\textbackslash TutorialLocal\_db")) \{\newline 
//    try \{\newline 
//        System.IO.Directory.Delete(@"C:\textbackslash tmp\textbackslash TutorialLocal\_db",true);\newline 
//    \} catch(Exception) \{ \}\newline 
//\}\newline 
//if(System.IO.Directory.Exists(@"C:\textbackslash tmp\textbackslash deploy"))\{\newline 
//    try \{\newline 
//        System.IO.Directory.Delete(@"C:\textbackslash tmp\textbackslash deploy",true);\newline 
//    \} catch(Exception) \{ \}\newline 
// \newline 
//\}
 }
\BoSSSexeSilent
\BoSSScmd{
/// and create, resp. open a \BoSSS database on a local drive.
var myLocalDb = OpenOrCreateDefaultDatabase();
 }
\BoSSSexe
\BoSSScmdSilent{
/// BoSSScmdSilent BoSSSexeSilent
databases;
 }
\BoSSSexeSilent
\BoSSScmd{
/// % ==================================================================
/// \section{Loading a BoSSS-Solver and Setting up a Simulation}
/// % ==================================================================
 }
\BoSSSexe
\BoSSScmd{
/// We have to initialize all batch systems that we want to use.
/// Normally, one would put these statements into the 
/// {\tt $\sim$/.BoSSS/etc/DBErc.cs}-file
var myBatch = new MiniBatchProcessorClient();
 }
\BoSSSexe
\BoSSScmd{
/// The batch processor for local jobs can be started separately (by launching
/// {\tt MiniBatchProcessor.exe}), or from the worksheet as follows.
/// In the latter case, it depends on the operating system, whether the 
/// \newline {\tt MiniBatchProcessor.exe} is terminated with the worksheet, or not.
MiniBatchProcessor.Server.StartIfNotRunning(false);
 }
\BoSSSexe
\BoSSScmd{
/// In this tutorial, we use the workflow management tools to simulate 
/// incompressible channel flow, therefore we have to import the namespace,
/// and repeat the steps from chapter \ref{IBM} in order to setup the
/// control object:
using BoSSS.Application.IBM\_Solver;
 }
\BoSSSexe
\BoSSScmd{
 % 
 }
\BoSSSexe
\BoSSScmd{
/// We create a grid with boundary conditions:
 }
\BoSSSexe
\BoSSScmd{
var xNodes       = GenericBlas.Linspace(0, 10 , 41); \newline 
var yNodes       = GenericBlas.Linspace(-1, 1, 9); \newline 
GridCommons grid = Grid2D.Cartesian2DGrid(xNodes, yNodes);\newline 
grid.EdgeTagNames.Add(1, "wall");  \newline 
grid.EdgeTagNames.Add(2, "Velocity\_Inlet");  \newline 
grid.EdgeTagNames.Add(3, "Pressure\_Outlet");\newline 
grid.DefineEdgeTags(delegate (double[] X) \{ \newline 
\btab double x = X[0];\newline 
\btab double y = X[1];\newline 
\btab byte et  = 0; \newline 
\btab if (Math.Abs(y - (-1)) <= 1.0e-8) \newline 
\btab \btab et = 1; // lower wall\newline 
\btab if (Math.Abs(y - (+1)) <= 1.0e-8) \newline 
\btab \btab et = 1; // upper wall\newline 
\btab if (Math.Abs(x - (0.0)) <= 1.0e-8) \newline 
\btab \btab et = 2; // inlet\newline 
\btab if (Math.Abs(x - (+10.0)) <= 1.0e-8) \newline 
\btab \btab et = 3; // outlet\newline 
\btab return et; \newline 
\});
 }
\BoSSSexe
\BoSSScmd{
/// And save it to the database:
 }
\BoSSSexe
\BoSSScmd{
myLocalDb.SaveGrid(ref grid);
 }
\BoSSSexe
\BoSSScmd{
 % 
 }
\BoSSSexe
\BoSSScmd{
/// Next, we create the control object for the incompressible simulation,
/// as in chapter \ref{IBM}:
 }
\BoSSSexe
\BoSSScmd{
// control object instantiation:\newline 
var c = new IBM\_Control();\newline 
// general description:\newline 
int k                = 1;\newline 
string desc          = "Steady state, channel, k" + k; \newline 
c.SessionName        = "SteadyStateChannel"; \newline 
c.ProjectDescription = desc;\newline 
c.Tags.Add("k"+k);\newline 
// setting the grid:\newline 
c.SetGrid(grid);\newline 
// DG polynomial degree\newline 
c.SetDGdegree(k);\newline 
// Physical parameters:\newline 
double reynolds            = 20; \newline 
c.PhysicalParameters.rho\_A = 1; \newline 
c.PhysicalParameters.mu\_A  = 1.0/reynolds;\newline 
// Timestepping properties:\newline 
c.Timestepper\_Scheme = IBM\_Control.TimesteppingScheme.ImplicitEuler; \newline 
c.dtFixed            = 1E20;  \newline 
c.NoOfTimesteps      = 1;\newline 
// Properties for the Picard Iterations:\newline 
c.MaxSolverIterations = 50; \newline 
c.MinSolverIterations = 1;
 }
\BoSSSexe
\BoSSScmd{
/// The specification of boundary conditions and initial values
/// is a bit more complicated if the job manager is used:
/// Since the solver is executed in an external program, the control object 
/// has to be saved in a file. For lots of complicated objects,
/// especially for delegates, C\# does not support serialization 
/// (converting the object into a form that can be saved on disk, or 
/// transmitted over a network), so a workaround is needed.
/// This is achieved e.g. by the \code{Formula} object, where a C\#-formula
/// is saved as a string.
 }
\BoSSSexe
\BoSSScmd{
var WallVelocity = new Formula("X => 0.0", false); // a time-indep. formula
 }
\BoSSSexe
\BoSSScmd{
/// Testing the formula:
WallVelocity.Evaluate(new[]\{0.0, 0.0\}, 0.0); // evaluationg at (0,0), at time 0
 }
\BoSSSexe
\BoSSScmd{
/// A disadvantage of string-formulas is that they look a bit ``alien''
/// within the worksheet; therefore, there is also a little hack which allows 
/// the conversion of a static memeber function of a static class into a 
/// \code{Formula} object:
 }
\BoSSSexe
\BoSSScmd{
static class StaticFormulas \{\newline 
\btab public static double VelX\_Inlet(double[] X) \{\newline 
\btab \btab //double x  = X[0];\newline 
\btab \btab double y  = X[0];\newline 
\btab \btab double UX = 1.0 - y*y;\newline 
\btab \btab return UX;\newline 
\btab \}  \newline 
 \newline 
\btab public static double VelY\_Inlet(double[] X) \{\newline 
\btab \btab return 0.0;\newline 
\btab \}      \newline 
\}
 }
\BoSSSexe
\BoSSScmd{
var InletVelocityX = GetFormulaObject(StaticFormulas.VelX\_Inlet);\newline 
var InletVelocityY = GetFormulaObject(StaticFormulas.VelY\_Inlet);
 }
\BoSSSexe
\BoSSScmd{
/// Finally, we set boundary values for our simulation. The initial values
/// are set to zero per default; for the steady-state simulation initial
/// values are irrelevan anyway:
/// Initial Values are set to 0
c.BoundaryValues.Clear(); \newline 
c.AddBoundaryValue("wall", "VelocityX", WallVelocity); \newline 
c.AddBoundaryValue("Velocity\_Inlet", "VelocityX", InletVelocityX);  \newline 
c.AddBoundaryValue("Velocity\_Inlet", "VelocityY", InletVelocityY); \newline 
c.AddBoundaryValue("Pressure\_Outlet");
 }
\BoSSSexe
\BoSSScmd{
/// % ==================================================================
/// \section{Deploying the jobs}
/// % ==================================================================
 }
\BoSSSexe
\BoSSScmd{
/// Finally, we are ready to deploy the job at the batch processor;
/// In a usual work flow scenario, we \emph{do not} want to (re-) submit the 
/// job every time we run the worksheet -- usually, one wants to run a job once.
/// 
/// The concept to overcome this problem is job activation. If a job is 
/// activated, the meta job manager first checks the databases and the batch 
/// system, if a job with the respective name and project name is already 
/// submitted. Only if there is no information that the job was ever submitted
/// or started anywhere, the job is submitted to the respective batch system.
 }
\BoSSSexe
\BoSSScmd{
/// 
/// First, a \code{Job}-object is created from the control object:
var JobLocal = c.CreateJob();
 }
\BoSSSexe
\BoSSScmd{
/// This job is not activated yet, it can still be configured:
 }
\BoSSSexe
\BoSSScmd{
JobLocal.Status;
 }
\BoSSSexe
\BoSSScmd{
/// One can change e.g. the number of MPI processes:
 }
\BoSSSexe
\BoSSScmd{
JobLocal.NumberOfMPIProcs = 1;
 }
\BoSSSexe
\BoSSScmd{
/// Then, the job is activated, resp. submitted to one batch system:
 }
\BoSSSexe
\BoSSScmd{
JobLocal.Activate(myBatch); // execute the job in 'myBatch'
 }
\BoSSSexe
\BoSSScmd{
/// All jobs can be listed using the workflow management:
 }
\BoSSSexe
\BoSSScmd{
WorkflowMgm.AllJobs
 }
\BoSSSexe
\BoSSScmd{
/// Check the present job status:
JobLocal.Status;
 }
\BoSSSexe
\BoSSScmd{
/// Here, we block until both of our jobs have finished:
WorkflowMgm.BlockUntilAllJobsTerminate(360);
 }
\BoSSSexe
\BoSSScmd{
/// We examine the output and error stream of the job on the HPC cluster:
/// This directly accesses the {\tt stdout}-redirection of the respective job
/// manager, which may contain a bit more information than the 
/// {\tt stdout}-copy in the session directory.
JobLocal.Stdout;
 }
\BoSSSexe
\BoSSScmd{
/// Additionally we display the error stream and hope that it is empty:
JobLocal.Stderr;
 }
\BoSSSexe
\BoSSScmd{
/// We can also obtain the session which was stored during the execution of the 
/// job:
 }
\BoSSSexe
\BoSSScmd{
var Sloc = JobLocal.LatestSession;\newline 
Sloc;
 }
\BoSSSexe
\BoSSScmd{
/// Finally, we check the status of our jobs:
 }
\BoSSSexe
\BoSSScmd{
JobLocal.Status;
 }
\BoSSSexe
