Skip to content

Analysis of boundary artifact of stochastic differential equation caused by reflection scheme

Notifications You must be signed in to change notification settings

Mauhing/Boundary-artifact-of-stochastic-differential-equation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Boundary artifact of stochastic differential equation

Analysis of boundary artifact of stochastic differential equation caused by reflection scheme.

This repo will generate the figure in my master thesis: https://ntnuopen.ntnu.no/ntnu-xmlui/handle/11250/2625252

This repository contain all the code for generate all the result in my master thesis. Most of the code is resulted to well mixed condition test. It is paralle computation code. This may be difficult to undstand the code at the beginning. Let us start with something simple.

def SDE_Single_Step(z,dt):
  # stochastic differential equation scheme.
  return z
def refelctive_scheme(z, H):
  # Boundary condition
  return z

T_end = 3600*24
dt = 10
H = 10
H_h = 2
N_b = 200
Ntime = T_end/dt
hist_ = 0
bins = np.linspace(0, H_h, N_b)
dz = bins[1] - bins[0]

for i in range(int(T_end/dt)):
  z = z + SDE_Single_Step(z,dt)
  temp, _ = np.histogram(z, bins=np.linspace(0,N_b))
  hist_ = (hist_*H) / ( dz))
  
hist_ = (hist_*/(Ntime+1))

where the last line is normalize the concentration. This is the code just for single particles. For many particle, we can just repeat this process and add the histogram together and divided by total particles since particles do not interact each other. The reader may found that the code I am using is a bit different. It is just because I am taking a count for the perfomance. But they are essentially doing the same thing.

Now, we assume we have 4 cores processor. It should be easy to parallelise the code since they do not interact each other. Let's say that we have Np so many particles. We can divide them in 4 and launch them in each processor. To do this, we define a function, called simulation, which will divide total particles in 4 and launch them in 4 proceses. We have also a function called parallel which is essentially doing the same above and return the histogram. And then, simulation wait for all 4 parallel process to complete and return. To the end. It gives out us the final output.

def oneStep(Z ,scheme, H, dt):
    
    Z_Origin = Z.copy()
    Z = scheme(Z, H, dt, Z.size)
    
    maskCross = ((H < Z) | (0 > Z)) 
    Crossing = Z_Origin[maskCross]
    
    Z = np.where(Z < 0, -Z, Z)
    Z = np.where(Z > H, 2*H - Z, Z)
    
    Landing = Z[maskCross]
    
    return Z, Crossing, Landing

def parallel(Tmax, dt, H, Testdepth, Np, Nbins, quene, queneCross, queneLand,
             scheme):

    np.random.seed()
    Ntime = int(Tmax / dt)

    hist_ = np.zeros((Nbins - 1, ), 'uint64')
    hist_Cross = np.zeros((Nbins - 1, ), 'uint64')
    hist_Land = np.zeros((Nbins - 1, ), 'uint64')

    #z = np.linspace(0, H, int(Np))
    z = np.random.uniform(0, H, int(Np))

    temp0, _ = np.histogram(z, bins=np.linspace(0, Testdepth, Nbins))
    hist_ = hist_ + temp0
    
    for i in range(Ntime):

        z, Cross, Land = oneStep(z, scheme, H, dt)

        #Adding the histogram
        ###
        temp0, _ = np.histogram(z, bins=np.linspace(0, Testdepth, Nbins))
        hist_ = hist_ + temp0

        temp2, _ = np.histogram(Cross, bins=np.linspace(0, Testdepth, Nbins))
        hist_Cross = hist_Cross + temp2

        temp3, _ = np.histogram(Land, bins=np.linspace(0, Testdepth, Nbins))
        hist_Land = hist_Land + temp3
        
        try:
            if (i % int(Ntime / 100) == 0):
                print("\r %6.2f" % (i * 100 / Ntime + 1),
                      "%",
                      end="\r",
                      flush=True)
        except ZeroDivisionError as err:
            None
            
    quene.put(hist_)
    queneCross.put(hist_Cross)
    queneLand.put(hist_Land)

    return None
    
def RunSimulation(NumberOfThread, Tmax, dt, H, Testdepth, Np, Nbins, scheme):
    print("Total number of process: ", NumberOfThread)
    SubNp = np.full((NumberOfThread, ), int(Np / NumberOfThread))
    SubNp[-1] = SubNp[-1] + (Np % NumberOfThread)
    
    Ntime = int(Tmax / dt)  #Number of time interval

    if (__name__ == '__main__'):

        threads = []
        quene = mp.Queue()
        queneCross = mp.Queue()
        queneLand = mp.Queue()

        for i in range(NumberOfThread):
            thread = mp.Process(target=parallel,
                                args=(Tmax, dt, H, Testdepth, SubNp[i], Nbins,
                                      quene, queneCross, queneLand, scheme))

            threads.append(thread)
            thread.start()  #starting calculation.

        for thread in threads:
            thread.join()  #waiting these processes finish.

    hist_ = np.zeros((Nbins - 1, ), 'float64')
    hist_Cross = np.zeros((Nbins - 1, ), 'float64')
    hist_Land = np.zeros((Nbins - 1, ), 'float64')

    for i in range(NumberOfThread):
        hist_ += quene.get()
        hist_Cross += queneCross.get()
        hist_Land += queneLand.get()
        
    bins = np.linspace(0, Testdepth, Nbins)
    dz = bins[1] - bins[0]
    hist_ = (hist_*H) / (Np * dz * (Ntime+1))
    
    midpoints = bins[:-1] + (bins[1]-bins[0]) / 2
    hist_Cross = hist_Cross / (np.sum(hist_Cross)*(midpoints[1]-midpoints[0]))
    hist_Land = hist_Land / (np.sum(hist_Land)*(midpoints[1]-midpoints[0]))

    return hist_, hist_Cross, hist_Land

This will be the engine to power the most WMC test in my master thesis. However, the reader may found that I have small modification for each file. It is ecentially just make it even faster, or let it to adapt to the mirrored domain.
Thank you

About

Analysis of boundary artifact of stochastic differential equation caused by reflection scheme

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published