@*
SimulationDriver.tmpl

Created by Graham Dennis on 2008-02-27
Modified by Liam Madge on 2013-09-11
Modified by Gregory Bogomiagkov on 2013-09-12

Copyright (c) 2008-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.SimulationDrivers._SimulationDriver

@from xpdeint.Vectors.VectorElement import VectorElement

@def description: Default Simulation Driver

@def functionImplementations
  @#
  @super
  @#
${topLevelSegmentFunctionImplementation}@slurp

  @#
@end def

@def runningSimulationCode
  @#
_segment0();
  @#
@end def

@def topLevelSegmentFunctionImplementation
  @#
void _segment0()
{
  @#
  @# And now insert the code for the features that apply in the top level sequence
  @set $featureOrdering = ['ErrorCheck', 'Stochastic']
  @set $dict = {'extraIndent': 0}
  ${insertCodeForFeatures('topLevelSequenceBegin', featureOrdering, dict), autoIndent=True}@slurp
  @set $extraIndent = dict['extraIndent']
  ${topLevelSequence.topLevelSequenceInnerContent, autoIndent=True, extraIndent=extraIndent}@slurp
  @#
  ${insertCodeForFeaturesInReverseOrder('topLevelSequenceEnd', featureOrdering, dict), autoIndent=True}@slurp
}
  @#
@end def


@def mainRoutine
  @#
int main(int argc, char **argv)
{
  ${mainRoutineInnerContent, autoIndent=True}@slurp
  
  return 0;
}
  @#
@end def

@def mainRoutineInnerContent
  @#
#ifdef __APPLE__
  #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
{
  IOPMAssertionID _powerAssertionID = 0;
  IOReturn __io_result = IOPMAssertionCreateWithDescription(
    kIOPMAssertionTypePreventUserIdleSystemSleep,
    CFSTR("XMDS simulation '${simulationName}' preventing user idle sleep"), // Assertion name
    NULL, // Assertion details
    NULL, // Human-readable reason
    NULL, // Localization bundle path
    (CFTimeInterval)0, // never timeout
    kIOPMAssertionTimeoutActionRelease,
    &_powerAssertionID
    );
  if (__io_result != kIOReturnSuccess) {
    _LOG(_WARNING_LOG_LEVEL, "Failed to disable user idle sleep\n");
  }
  // Note, this power assertion is automatically released when the process quits.
}
  #endif
#endif

  
  @set $preAllocationFeatureOrdering = ['Arguments', 'Driver', 'ChunkedOutput']
${insertCodeForFeatures('preAllocation', $preAllocationFeatureOrdering)}@slurp
  

  @set vectors = set([v for v in $templates if isinstance(v, VectorElement)])
${setVectorAllocSizes(vectors)}@slurp
  @#
  @for field in $fields
${field.allocate}@slurp
  @end for

  @for $mg in $momentGroups
${mg.allocate}@slurp
  @end for

  @*
    And now insert the code for the features that apply in the main function
  *@
  @set $featureOrdering = ['Bing', 'Validation', 'Driver', 'OpenMP', 'Stochastic', 'TransformMultiplexer', 'Benchmark', 'Output']
${insertCodeForFeatures('mainBegin', $featureOrdering)}@slurp

@# This needs to be extracted into a function so that it can be indented further if necessary
/* Code that actually does stuff goes here */
${runningSimulationCode}@slurp

${insertCodeForFeaturesInReverseOrder('mainEnd', $featureOrdering)}@slurp
  @#
  @for $field in $fields
${field.free}@slurp
  @end for

  @#
@end def

@def setVectorAllocSizes($vectors)
  @#
  @for vector in vectors
    @for basis in vector.basesNeeded
${vector.allocSize} = MAX(${vector.allocSize}, ${vector.field.sizeInBasis(basis)} * _${vector.id}_ncomponents);
    @end for
  @end for
  @#
@end def

@def mainBegin($dict)
  @#
  @set $initialisedDimRepArrays = set()
  @#
  @for field in $fields
    @#
    @for dim in field.dimensions
      @for dimRep in [dimRep for dimRep in dim.representations if dimRep and not dimRep.arrayName in initialisedDimRepArrays]
${dimRep.initialiseArray}@slurp
        @silent initialisedDimRepArrays.add(dimRep.arrayName)
      @end for
    @end for
  @end for
  @for $mg in $momentGroups
${mg.outputField.initialise}@slurp
  @end for
  @#
@end def
