Source code for edelweissfe.timesteppers.simpletimestepper

# -*- coding: utf-8 -*-
#  ---------------------------------------------------------------------
#
#  _____    _      _              _         _____ _____
# | ____|__| | ___| |_      _____(_)___ ___|  ___| ____|
# |  _| / _` |/ _ \ \ \ /\ / / _ \ / __/ __| |_  |  _|
# | |__| (_| |  __/ |\ V  V /  __/ \__ \__ \  _| | |___
# |_____\__,_|\___|_| \_/\_/ \___|_|___/___/_|   |_____|
#
#
#  Unit of Strength of Materials and Structural Analysis
#  University of Innsbruck,
#  2017 - today
#
#  Alexander Dummer alexander.dummer@uibk.ac.at
#
#  This file is part of EdelweissFE.
#
#  This library is free software; you can redistribute it and/or
#  modify it under the terms of the GNU Lesser General Public
#  License as published by the Free Software Foundation; either
#  version 2.1 of the License, or (at your option) any later version.
#
#  The full text of the license can be found in the file LICENSE.md at
#  the top level directory of EdelweissFE.
#  ---------------------------------------------------------------------
# Created on Sat Jan  21 12:18:10 2017

from edelweissfe.journal.journal import Journal
from edelweissfe.timesteppers.base.timestepperbase import TimeStepperBase
from edelweissfe.timesteppers.timestep import TimeStep
from edelweissfe.utils.exceptions import ReachedMaxIncrements, ReachedMinIncrementSize


[docs] class SimpleTimeStepper(TimeStepperBase): """Divides a step into increments of a fixed size, or of a size enforced by the solver, after one zero increment. The zero increment comes first, so that an explicit integrator can build its initial state (mass, internal force, contact) before taking a step. It is numbered 0; the increments after it are numbered from 1. A step resumed from a checkpoint does not repeat it: whether it was done is part of the stepper's state. Parameters ---------- currentTime The start time of the step. stepLength The total length of the step. startIncrement The size of the start increment, relative to the step length. maxIncrement The maximum size of an increment, relative to the step length. minIncrement The minimum size of an increment, relative to the step length. maxNumberIncrements The maximum number of allowed increments. journal The journal instance for logging purposes. """ identification = "SimpleTimeStepper" checkpointedState = { "currentTime": float, "zeroIncrementDone": bool, "totalIncrements": int, "finishedStepProgress": float, "increment": float, "enforcedTimeIncrement": float, } def __init__( self, currentTime: float, stepLength: float, startIncrement: float, maxIncrement: float, minIncrement: float, maxNumberIncrements: float, journal: Journal, ): self.startIncrement = startIncrement self.maxIncrement = maxIncrement self.minIncrement = minIncrement self.maxNumberIncrements = maxNumberIncrements self.stepLength = stepLength self.journal = journal #: The start time of the step. self.currentTime = currentTime #: Whether the zero increment was accepted. self.zeroIncrementDone = False #: The number of increments accepted after the zero increment. self.totalIncrements = 0 #: The accepted progress within the step, from 0 to 1. self.finishedStepProgress = 0.0 #: The size of the next increment, relative to the step length. self.increment = min(startIncrement, maxIncrement) #: The time increment the solver enforces, or None. self.enforcedTimeIncrement = None
[docs] def isFinished(self) -> bool: return self.zeroIncrementDone and self.finishedStepProgress >= (1.0 - 1e-15)
[docs] def isAtStepStart(self) -> bool: return not self.zeroIncrementDone
[docs] def numberOfIncrementsDone(self) -> int: return self.totalIncrements
[docs] def proposeTimeStep(self) -> TimeStep: progress = self.finishedStepProgress if not self.zeroIncrementDone: return TimeStep( 0, 0.0, progress, 0.0, self.stepLength * progress, self.currentTime + self.stepLength * progress ) if self.totalIncrements >= self.maxNumberIncrements: self.journal.message("Reached maximum number of increments", self.identification) raise ReachedMaxIncrements() if self.increment > self.maxIncrement: self.increment = self.maxIncrement if self.enforcedTimeIncrement is not None: self.increment = self.enforcedTimeIncrement / self.stepLength remainder = 1.0 - progress if remainder < self.increment: self.increment = remainder progress += self.increment return TimeStep( self.totalIncrements + 1, self.increment, progress, self.stepLength * self.increment, self.stepLength * progress, self.currentTime + self.stepLength * progress, )
[docs] def acceptTimeStep(self, timeStep: TimeStep): if not self.zeroIncrementDone: self.zeroIncrementDone = True return self.finishedStepProgress = timeStep.stepProgress self.totalIncrements += 1
[docs] def rejectTimeStep(self, cutbackFactor: float): if not self.zeroIncrementDone: self.journal.errorMessage("Failed zero increment", self.identification) raise ReachedMinIncrementSize() # The last increment of a step, the remainder, may be below the minimum size already. if self.increment <= self.minIncrement: self.journal.errorMessage("Cannot reduce increment size", self.identification) raise ReachedMinIncrementSize() self.increment = min(max(self.increment * cutbackFactor, self.minIncrement), self.maxIncrement) if self.enforcedTimeIncrement is not None: self.enforcedTimeIncrement = self.increment * self.stepLength self.journal.message("Cutback to increment size {:}".format(self.increment), self.identification, 1)
[docs] def enforceTimeIncrement(self, timeIncrement: float): self.enforcedTimeIncrement = timeIncrement
[docs] def changeIncrementSize(self, scaleFactor: float): if not self.zeroIncrementDone: return self.increment = min(max(self.increment * scaleFactor, self.minIncrement), self.maxIncrement) self.journal.message("New increment size {:}".format(self.increment), self.identification, 1)
[docs] def preventIncrementIncrease(self): """This time stepper never increases the increment size automatically, hence this is a no-op."""