@*
Simulation.tmpl

Created by Graham Dennis on 2007-08-23.

Copyright (c) 2007-2012, Graham Dennis

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*@
@#
@extends xpdeint.ScriptElement
@#
@attr $name = ''
@attr $id = ''
@#
@# First check we have at least Cheetah version 2.0.1
@if __CHEETAH_versionTuple__ < (2, 0, 1, 'final', 0)
  @silent raise AssertionError("xmds2 requires at least Cheetah version "
                               "2.0.1. You currently have %s." % __CHEETAH_version__)
@end if
@#
@#
@# Base simulation template
// ********************************************************
// simulation logging

#define _SAMPLE_LOG_LEVEL             (1 << 0)
#define _SEGMENT_LOG_LEVEL            (1 << 1)
#define _PATH_LOG_LEVEL               (1 << 2)
#define _SIMULATION_LOG_LEVEL         (1 << 3)
#define _WARNING_LOG_LEVEL            (1 << 4)
#define _ERROR_LOG_LEVEL              (1 << 5)
#define _NO_ERROR_TERMINATE_LOG_LEVEL (1 << 6)
#define _ALL_LOG_LEVELS        _SAMPLE_LOG_LEVEL|_SEGMENT_LOG_LEVEL|_PATH_LOG_LEVEL|_SIMULATION_LOG_LEVEL|_WARNING_LOG_LEVEL|_ERROR_LOG_LEVEL|_NO_ERROR_TERMINATE_LOG_LEVEL
#define _LOG_LEVELS_BEING_LOGGED (${features['Driver'].logLevelsBeingLogged})

#define real Re
#define imag Im

#include <complex>

#undef real
#undef imag


#include <stdio.h>

@set $featureOrdering = ['Driver']
#define _LOG(logLevel, ...) \
  do { \
    if (logLevel & _LOG_LEVELS_BEING_LOGGED) { \
  @set $dict = {'extraIndent': 0}
      ${insertCodeForFeatures('logFunctionBegin', $featureOrdering, $dict), autoIndent=True}@slurp
  @set $extraIndent = dict['extraIndent']
      ${logFunctionInnerContent, autoIndent=True, extraIndent=extraIndent}@slurp
      ${insertCodeForFeaturesInReverseOrder('logFunctionEnd', $featureOrdering, $dict), autoIndent=True}@slurp
      if (logLevel & (_ERROR_LOG_LEVEL | _NO_ERROR_TERMINATE_LOG_LEVEL)) \
        exit(logLevel == _ERROR_LOG_LEVEL); \
    } \
  } while (0)

// ********************************************************
// simulation includes

#include <xpdeint_platform.h>
#include <cmath>
#include <string>
#include <cstring>
#include <fstream>
#include <sstream>
#include <cstdlib>

#if CFG_OSAPI == CFG_OSAPI_POSIX // These are POSIX headers (i.e. non-windows)
  #include <sys/time.h>
#endif // POSIX

#ifdef __APPLE__
  #include <Availability.h>
  #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
    #define OS_OBJECT_USE_OBJC 0 // Don't make dispatch and xpc objects Objective-C objects.
    #include <IOKit/pwr_mgt/IOPMLib.h> // To disable user idle sleep on Mountain Lion
  #endif
#endif

#include <time.h>
#include <list>
#include <vector>
#include <algorithm>

@for $child in $children
  @# Prevent writing zero-length defines
  @set $result = $child.implementationsForFunctionName('includes')
  @if $result and not $result.isspace()
${result}@slurp

  @end if
@end for

@set $realType = {'single': 'float', 'double': 'double'}[$precision]
typedef long integer;
typedef ${realType} real;
typedef std::complex<real> XMDSComplexType;

#include <xpdeint.h>

#define complex XMDSComplexType

const complex i(0.0, 1.0);

using namespace std;

#if CFG_COMPILER == CFG_COMPILER_ICC
  //
  // Disable ICC's warning: label was declared but never referenced
  //
  #pragma warning ( disable : 177 )
#endif

inline void *xmds_malloc(size_t size);

// ********************************************************
// DEFINES
// ********************************************************
@# only loop over the elements that implement the defines function
@for $child in $children
  @# Prevent writing zero-length defines
  @set $result = $child.implementationsForFunctionName('defines')
  @if result and not result.isspace()

// ********************************************************
//   $child.description defines
$result@slurp
  @end if
@end for


// ********************************************************
// GLOBALS
// ********************************************************

@# only loop over the elements that implement the globals function
@for $child in $children
  @# Prevent writing zero-length globals
  @set $result = $child.implementationsForFunctionName('globals')
  @if result and not result.isspace()

// ********************************************************
//   $child.description globals
$result@slurp
  @end if
@end for


// ********************************************************
// FUNCTION PROTOTYPES
// ********************************************************
@# only loop over the elements that implement the prototypes function
@for $child in $children
  @# Prevent writing zero-length globals
  @set $result = $child.implementationsForFunctionName('functionPrototypes')
  @if result and not result.isspace()

// ********************************************************
//   $child.description function prototypes
$result@slurp
  @end if
@end for

// ********************************************************
// MAIN ROUTINE
// ********************************************************
$features.Driver.mainRoutine@slurp

// ********************************************************
// FUNCTION IMPLEMENTATIONS
// ********************************************************

inline void *xmds_malloc(size_t size)
{
  void *retPointer = _xmds_malloc(size);
  if ( !retPointer )
    _LOG(_ERROR_LOG_LEVEL, "ERROR: Couldn't allocate %zu bytes of memory!", size);
  return retPointer;
}

@# only loop over the elements that implement the prototypes function
@for $child in $children
  @# Prevent writing zero-length function implementations
  @set $result = $child.implementationsForFunctionName('functionImplementations')
  @if result and not result.isspace()

// ********************************************************
//   $child.description function implementations
$result@slurp
  @end if
@end for

@def logFunctionInnerContent
  @#
if (logLevel & (_ERROR_LOG_LEVEL | _WARNING_LOG_LEVEL)) \
    printf("%s:%i: ", __FILE__, __LINE__); \
printf(__VA_ARGS__); \
fflush(stdout); \
  @#
@end def
