Logo Search packages:      
Sourcecode: adun.app version File versions  Download package

AdunSimulator.m

/*
   Project: Adun

   Copyright (C) 2005 Michael Johnston & Jordi Villa-Freixa

   Author: Michael Johnston

   This application 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 application 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
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#include "AdunKernel/AdunSimulator.h"

@class NewtonianSimulator;
@class LangevinSimulator;

00027 @implementation AdSimulator

//Subclasses should override this method if they need to peform 
//update related tasks when a systems status changes

00032 - (void) handleChangeInSystemStatus: (NSNotification*) aNotification
{
      NSString* previousStatus, *currentStatus;
      NSDictionary* infoDict;

      //We are interested in systems who change from "active" or to "active"
      
      infoDict = [aNotification userInfo];
      previousStatus = [infoDict objectForKey:@"PreviousStatus"];
      currentStatus = [infoDict objectForKey:@"CurrentStatus"];

      if(!([previousStatus isEqual: @"Active"] || 
            [currentStatus isEqual: @"Active"]))
      {
            return;
      }
      
      //It is simplest to just reacquire the new active (non interaction) subsystems
      
      subsystems = [system systemsOfType: @"Standard" withStatus: @"Active"];
}

- (void) emptyPool
{
      [pool release];
      pool = [[NSAutoreleasePool alloc] init];
}

00060 - (void) endSimulation
{
      endSimulation = YES;
}

- (void) checkFloatingPointErrors
{
      int raised;
      NSMutableDictionary* errorInfo;
      NSError* error;

      /*
       * We want to detect floating point errors since they
       * will affect the stability of our simulation.
       * The errors we are detecting are based on IEEE754 standard
       * 1 - Invalid Operation
       * 2 - Division by Zero
       * 3 - Overflow
       * 4 - Underflow
       * 5 - Inexact
       * However error 5 is common since all irrational and transcendental
       * numbers are inexact and we may be adding many numbers who differ by more than 
       * DBL_EPSILON so we wont do anything in this case .
       * Error 4 leads to a slow loss of precision - however it may occur 
       * that tiny forces and energies are calculated in the course of
       * a simulation. In this case we will just log when this happens and 
       * let Error 2 handle cases where this will lead to a catastrophic error
       * (due to the result being zero).
       * See the Arithmetic section of the libc manual for more detail.
       */

      raised = fetestexcept(floatingPointExceptionMask);

      #ifdef FE_INVALID
      if(raised & FE_INVALID) 
      {
            errorInfo = [NSMutableDictionary dictionary];
            [errorInfo setObject: @"Detected floating point exception during simulation."
                  forKey: @"NSLocalizedDescriptionKey"];
            [errorInfo setObject: @"Exception due to an invalid operation."
                  forKey: @"AdDetailedDescriptionKey"];
            [errorInfo setObject: @"This is a critical error and likely due to a bug in an underlying algorithm.\n\
Please contact the Adun developers with information regarding the simulation you were running when this occurred.\n\
(Options, System, Results etc)\n"
                  forKey: @"NSRecoverySuggestionKey"];
            error = [NSError errorWithDomain: @"AdKernelErrorDomain"
                              code: 2
                              userInfo: errorInfo];
            feclearexcept(FE_ALL_EXCEPT);
            [[NSException exceptionWithName: @"AdFloatingPointException"
                  reason: @"Caught a IEEE74 floating point exception"
                  userInfo: [NSDictionary dictionaryWithObject: error
                              forKey: @"AdKnownExceptionError"]]
                  raise];
      }
      #endif

      #ifdef FE_OVERFLOW
      if(raised & FE_OVERFLOW)
      {
            errorInfo = [NSMutableDictionary dictionary];
            [errorInfo setObject: @"Detected floating point exception during simulation."
                  forKey: @"NSLocalizedDescriptionKey"];
            [errorInfo setObject: @"Exception due to overflow"
                  forKey: @"AdDetailedDescriptionKey"];
            [errorInfo setObject: @"This error indicates infinities entering the simulation.\n\
This is likely an indication of the simulation exploding due to excessive forces.\nUnrelaxed starting structures are\
a possible explanation.\nIn this case it is recommended you run an initial simulation with a smaller time step to relax\
the molecule.\nIt is also recommened that you examine the data collected so far which will provide more information on\
the cause.\n)"
                  forKey: @"NSRecoverySuggestionKey"];
            error = [NSError errorWithDomain: @"AdKernelErrorDomain"
                              code: 2
                              userInfo: errorInfo];
            feclearexcept(FE_ALL_EXCEPT);
            [[NSException exceptionWithName: @"AdFloatingPointException"
                  reason: @"Caught a IEEE74 floating point exception"
                  userInfo: [NSDictionary dictionaryWithObject: error
                              forKey: @"AdKnownExceptionError"]]
                  raise];
      }
      #endif

      #ifdef FE_DIVBYZERO
      if(raised & FE_DIVBYZERO)
      {
            errorInfo = [NSMutableDictionary dictionary];
            [errorInfo setObject: @"Detected floating point exception during simulation."
                  forKey: @"NSLocalizedDescriptionKey"];
            [errorInfo setObject: @"Exception due to divide by zero"
                  forKey: @"AdDetailedDescriptionKey"];
            [errorInfo setObject: @"This error could be due to a underflow event or a programming bug.\n\
Please contact the Adun developers with information regarding the simulation you were running when this occurred.\n\
(Options, System, Results etc)\n"
                  forKey: @"NSRecoverySuggestionKey"];
            error = [NSError errorWithDomain: @"AdKernelErrorDomain"
                              code: 2
                              userInfo: errorInfo];
            feclearexcept(FE_ALL_EXCEPT);
            [[NSException exceptionWithName: @"AdFloatingPointException"
                  reason: @"Caught a IEEE74 floating point exception"
                  userInfo: [NSDictionary dictionaryWithObject: error
                              forKey: @"AdKnownExceptionError"]]
                  raise];
      }
      #endif

      #ifdef FE_UNDERFLOW 
      if(raised & FE_UNDERFLOW)
      {
            NSWarnLog(@"Detected an underflow exception.");
            NSWarnLog(@"This could be the result of extremly small forces and/or energies being calculated.");
            NSWarnLog(@"Such events are not uncommon but will lead to a loss of precision.");
            NSWarnLog(@"It is possible that underflows could lead to zeros entering the calculation and\
'divide by zero' errors as a result\n. However these will be caught independantly if they occur");
            NSWarnLog(@"Continuing simulation");
            feclearexcept(FE_ALL_EXCEPT);
      }
      #endif

      //clear any FE_INEXACT exceptions

      feclearexcept(FE_ALL_EXCEPT);
}


/**************

Object Creation

***************/

+ (id) objectForEnvironment: (id) object observes: (BOOL) value
00192 {
      id simulator;

      simulator = nil;
      if(object != nil)
      {
            if([[object valueForKey: @"ExplicitSolvent"] boolValue])
                  simulator = [[NewtonianSimulator alloc] initWithEnvironment: object observe: value];
            else if([[object valueForKey: @"SimulationType"] isEqual: @"Langevin"])
                  simulator =  [[LangevinSimulator alloc] initWithEnvironment: object observe: value];
            else if([[object valueForKey: @"SimulationType"] isEqual: @"Newtonian"])
                  simulator = [[NewtonianSimulator alloc] initWithEnvironment: object observe: value];
            else
                  [NSException raise: NSInvalidArgumentException
                        format: [NSString stringWithFormat: 
                        @"Environment contains invalid value for SimulationType - %@." ,
                         [object valueForKey: @"SimulationType"]]];
      }
      else
            simulator = [[NewtonianSimulator alloc] initWithEnvironment: object observe: value];

      return [simulator autorelease];
}


+ (id) objectForEnvironment: (id) object
00218 {
      id simulator;

      simulator = nil;
      if(object != nil)
      {
            if([[object valueForKey: @"ExplicitSolvent"] boolValue])
                  simulator = [[NewtonianSimulator alloc] initWithEnvironment: object observe: YES];
            else if([[object valueForKey: @"SimulationType"] isEqual: @"Langevin"])
                  simulator =  [[LangevinSimulator alloc] initWithEnvironment: object observe: YES];
            else if([[object valueForKey: @"SimulationType"] isEqual: @"Newtonian"])
                  simulator = [[NewtonianSimulator alloc] initWithEnvironment: object observe: YES];
            else
                  [NSException raise: NSInvalidArgumentException
                        format: [NSString stringWithFormat: 
                        @"Environment contains invalid value for SimulationType - %@." ,
                         [object valueForKey: @"SimulationType"]]];
      }
      else
            simulator = [[NewtonianSimulator alloc] initWithEnvironment: object observe: YES];

      return [simulator autorelease];
}

- (id) init
{
      return [self initWithEnvironment: nil];
}

- (id) initWithEnvironment: (id) object
00248 {
      return [self initWithEnvironment: object observe: YES];
}

- (id) initWithEnvironment: (id) object observe: (BOOL) value
00253 {
      if(self = [super initWithEnvironment: object observe: value])
      {
            endSimulation = NO;
            if(environment == nil)
            {
                  no_of_steps = 1000;
                  target_temperature = 300;
                  time_step = 1.0;
                  checkFPErrorInterval = 10;
            }
            else
            {
                  no_of_steps = [[environment valueForKey: @"NumberConfigurations"] intValue];
                  target_temperature = [[environment valueForKey: @"TargetTemperature"] doubleValue];
                  time_step = [[environment valueForKey: @"TimeStep"] doubleValue];
                  checkFPErrorInterval = [[environment valueForKey: @"CheckFPErrorInterval"] intValue];
            }

            NSDebugLLog(@"AdunSimulator", @"The number of steps is %d", no_of_steps);
            timefac = time_step*0.5;
            timefac_sq = timefac*time_step;

            timer = [AdTimer new];  
            [timer sendMessage: @selector(emptyPool)
                  toObject: self
                  interval: 200
                  name: @"Autorelease"];
            [timer sendMessage: @selector(checkFloatingPointErrors)
                  toObject: self
                  interval: checkFPErrorInterval
                  name: @"FloatingPointErrors"];
      }     
      
      return self;
}

- (void) dealloc
{
      [subsystems release];
      [timer release];
      [system release];
      [forceField release];
      [super dealloc];
}

//FIXME: Temporary method
- (void) clearTimer
00301 {
      [timer removeMessageWithName: @"Autorelease"];
      [timer removeMessageWithName: @"FloatingPointErrors"];
}

/************

Object Accessors

*************/

- (void) production
{
      [NSException raise: NSInternalInconsistencyException
            format: [NSString stringWithFormat:
            @"(%@) %@ is an abstract method. You need to use a concrete subclass of this class", 
            NSStringFromClass([self class]), NSStringFromSelector(_cmd)]];
}

- (AdSystemNode*) system
00321 {
      return system;
}

- (void) setSystem: (AdSystemNode*) object 
00326 {
      [notificationCenter removeObserver: self
            name: @"AdSystemStatusDidChangeNotification"
            object: system];

      [system release];
        system = [object retain];
      if(subsystems != nil)
            [subsystems release];
      subsystems = [system systemsOfType: @"Standard"
                  withStatus: @"Active"];
      [subsystems retain];          

      [notificationCenter addObserver: self
            selector: @selector(handleChangeInSystemStatus:)
            name: @"AdSystemStatusDidChangeNotification"
            object: system];
            
}

- (AdForceFieldManager*) forceField
00347 {
      return forceField;
}

- (void) setForceField: (AdForceFieldManager*) object 
00352 {
      [forceField release];
      forceField = [object retain];
}

- (void) setNumberOfSteps: (int) aNumber
{
      no_of_steps = aNumber;
      [self updateDependantsOfKey: @"NumberOfConfigurations"];    
}

- (void) setTargetTemperature: (double) aValue
00364 {
      target_temperature = aValue;
}

- (double) targetTemperature
00369 {
      return target_temperature;
}

- (double) timeStep
00374 {
      return time_step;
}

- (void) setTimeStep: (double) stepSize
00379 {
      time_step = stepSize;
      timefac = time_step*0.5;
      timefac_sq = time_step*time_step*0.5;
}

- (int) currentStep
00386 {
      return currentStep;
}

- (int) numberOfSteps
00391 {
      return no_of_steps;
}

- (AdTimer*) timer
00396 {
      return timer;
}

@end
 

Generated by  Doxygen 1.6.0   Back to index