<commit_before># Generic Parareal Implementation
# Updated 12/6/2014

from mpi4py import MPI
import numpy as np
import time

from serial_euler import forward_euler

# Parareal begin
def startParareal(deriv, init, k, tmin, tmax, numSteps, comm):
  '''Starts running k iterations of the parareal algorithm.
  In each iteration, the program runs the coarse method in serial, then fine corrections in parallel'''

  # get a coarse answer
  u = serial_coarse(deriv, init, tmin, tmax, numSteps)[:,0]

  # fine time steps
  qualityFactor = 100
  fine = numSteps * qualityFactor

  # rethink logic here!
  if k > 1:
    for iteration in xrange(k-1):

      # get a coarse answer
      u = serial_coarse(deriv, init, tmin, tmax, numSteps)[:,0]

      # pass in a coarse answer to refine and correct
      corrections = parallel_corrections(deriv, u, time, comm, p_root=0)

      # update u with the corrections
      u += corrections

  return u

def serial_coarse(deriv, init, tmin, tmax, numSteps):
  '''Runs a coarse numerical method in serial, as part of the parareal algorithm'''
  # call forward euler
  return forward_euler(deriv, init, tmin, tmax, numSteps)

def parallel_corrections(u, tmin, tmax, numSteps, comm, p_root=0):
  '''Parallel Portion of the Parareal Algorithm
  Assumes the arrays exist on process p_root and returns the result to
  process p_root for a given iteration.
  By default, p_root = process 0.'''
  rank = comm.Get_rank()
  size = comm.Get_size()

  # Save the number of tasks to a variable
  # numtasks = len(u)

  # Start and end indices of the local dot product computed by function to allow for undivisble sizes
  start = getStart(numtasks, size, rank)
  end = getStart(numtasks, size, rank + 1)

  # Compute the partial dot product
  #local_dot = serial_dot(a[start:end], b[start:end])

  # Gather the partial results to the root process
  result = comm.gather(local_dot, root=p_root)

  return result

def getStart(numtasks, size, rank):
  # Offset by rank to account for n+1 spaces
  if rank < numtasks % size:
    return (numtasks / size + 1) * rank
    
  # Offset only by max numtasks % size
  else:
    return numtasks / size * rank + numtasks % size


if __name__ == '__main__':
  comm = MPI.COMM_WORLD
  rank = comm.Get_rank()

  # Example specific parameters and derivatives with IC
  def deriv(t, u):
    return lam * u

  init = np.array([1.])

  tmin = 0.
  tmax = 1.
  numSteps = 100

  init = np.array([1.])
  ###

  # Communciation barrier and timing function of MPI
  comm.barrier()
  p_start = MPI.Wtime()

  # Use parareal algorithm
  p_result = startParareal(deriv, init, tmin, tmax, step, comm)

  # Communciation barrier and ending time with MPI timing function
  comm.barrier()
  p_stop = MPI.Wtime() 

  # Check and output results on process 0
  if rank == 0:

    # compute serial result
    s_start = time.time()
    s_result = forward_euler(deriv, init, 0, 1, 0.01)[:,0]
    s_stop = time.time()

    # compute exact result
    e_result = np.exp(np.linspace(tmin, tmax, len(res)))
<commit_msg>basic logic of parareal complete - uncompiled<commit_after># Generic Parareal Implementation
# Updated 12/6/2014

# TODO 
# Confirm that Euler_Step function does not repeat calculations - else should memoize and look up

from mpi4py import MPI
import numpy as np
import time
import copy

from serial_euler import forward_euler
from serial_euler import forward_euler_step

# Parareal begin
def startParareal(deriv, init, k, tmin, tmax, numSteps, qualityFactor = 100, comm):
  '''Starts running k iterations of the parareal algorithm.
  In each iteration, the program runs the coarse method in serial, then fine corrections in parallel
  The result is only gathered to the root process at every iteration'''

  rank = comm.Get_rank()
  size = comm.Get_size()

  dt = (tmax-tmin) / (numSteps - 1)

  # upast and unext vectors
  upast = np.zeros(numSteps)
  unext = np.zeros(numSteps)

  # if further iterations are required
  if k > 1:
    for iteration in xrange(k-1):

      # pass in a coarse answer to refine and correct, bectorized
      corrections = parallel_corrections(deriv, upast, tmin, tmax, numSteps, qualityFactor, comm, p_root=0)

      if rank == 0:
        # get a coarse answer for the next iteration, vectorized
        unext = serial_coarse(deriv, upast, dt, tmin, tmax, numSteps)[:,0]

        # update unext for next iteration
        upast = copy.copy(unext)

        # update unext with corrections computed with upast
        # TODO check the edge case - this is correct?
        for ind in xrange(numSteps-1):
          unext[ind+1] += unext[ind] + corrections[ind]

  return unext

def serial_coarse(deriv, upast, dt, tmin, tmax, numSteps):
  '''Runs a coarse numerical method in serial, as part of the parareal algorithm.
  Will call the stepwise g_coarse function per step'''

  # initialize times
  times = np.linspace(time_min, time_max, numSteps)[1:]

  # call forward euler per step and store in vector
  for ind in xrange(numSteps):
    # get a coarse answer
    upast[ind] = serial_coarse(deriv, times[ind], u[ind], dt)
  return upast

def parallel_corrections(upast, tmin, tmax, numSteps, qualityFactor, comm, p_root=0):
  '''Parallel Portion of the Parareal Algorithm
  Divides the work based on the unext vector, into equal parameters
  Gathers the result on process p_root for the given iteration.
  By default, p_root = process 0.'''

  rank = comm.Get_rank()
  size = comm.Get_size()

  # Save the number of tasks
  numtasks = len(numSteps)

  # values for the fine computations
  fineNumSteps = numSteps*factor
  fineDt = dt / factor

  # broadcast upast
  upast = comm.broadcast(upast, root=p_rot)

  # Start and end indices of the times to divide into with a +1 for python range offset
  start = getStart(numtasks, size, rank)
  end = getStart(numtasks, size, rank + 1)

  # initialize times
  times = np.linspace(time_min, time_max, numSteps)[1:]

  # in a loop, compute fine and then corrections one piece at a time that processor is responsible for, serially
  while (start < end):
    fineResult = forward_euler(deriv, upast[start], times[start], times[start+1], fineNumSteps)[:,0]

    # get difference for the last time step of the fine result and compare to coarse result answer for same time
    difference = fineResult[-1] - upast[start]
    # concatenate the local results
    local_unext = np.concatenate(local_unext, difference)

    # move to solve next step
    start += 1

  # Gather the partial results to the root process
  result = comm.gather(local_unext, root=p_root)

  return result

def getStart(numtasks, size, rank):
  '''Returns optimally equal partioned index for the begin of the assigned array to divide'''
  # Offset by rank to account for n+1 spaces
  if rank < numtasks % size:
    return (numtasks / size + 1) * rank
    
  # Offset only by max numtasks % size
  else:
    return numtasks / size * rank + numtasks % size


if __name__ == '__main__':
  comm = MPI.COMM_WORLD
  rank = comm.Get_rank()

  # Example specific parameters and derivatives with IC
  def deriv(t, u):
    return lam * u

  init = np.array([1.])

  tmin = 0.
  tmax = 1.
  numSteps = 100

  init = np.array([1.])
  ###

  # Communciation barrier and timing function of MPI
  comm.barrier()
  p_start = MPI.Wtime()

  # Use parareal algorithm
  p_result = startParareal(deriv, init, tmin, tmax, step, comm)

  # Communciation barrier and ending time with MPI timing function
  comm.barrier()
  p_stop = MPI.Wtime() 

  # Check and output results on process 0
  if rank == 0:

    # compute serial result
    s_start = time.time()
    s_result = forward_euler(deriv, init, tmin, tmax, numSteps)[:,0]
    s_stop = time.time()

    # compute exact result
    e_result = np.exp(np.linspace(tmin, tmax, len(res)))

{'fraction_non_alphanumeric': 0.08791490452390106, 'fraction_numerical': 0.00986799948737665, 'mean_word_length': 3.4953917050691246, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4390970', 'n_tokens_mistral': 2624, 'n_tokens_neox': 2468, 'n_words': 932}