Package Owntools

@author: Alexandre Sac–Morane alexandre.sac-morane@uclouvain.be

This file contains the different functions used in the simulation.

Expand source code
# -*- coding: utf-8 -*-
"""
@author: Alexandre Sac--Morane
alexandre.sac-morane@uclouvain.be

This file contains the different functions used in the simulation.
"""

#-------------------------------------------------------------------------------
#Librairy
#-------------------------------------------------------------------------------

import os
import math
import numpy as np
from pathlib import Path
from scipy.ndimage import binary_dilation

#-------------------------------------------------------------------------------

def index_to_str(j):
  '''
  An integer is converted to a float with 3 components

    Input :
        a number (a float)
    Output :
        a string with 3 components (a string)
  '''
  if j < 10:
      j_str = '00'+str(j)
  elif 10 <= j and j < 100:
      j_str = '0'+str(j)
  else :
      j_str = str(j)
  return j_str

#-------------------------------------------------------------------------------

def Sort_Files(dict_algorithm):
     '''
     Sort files generated by MOOSE to different directories

        Input :
            an algorithm dictionnary (a dict)
        Output :
            Nothing but files are sorted
     '''

     os.rename(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_out.e','Output/'+dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_out.e')
     os.rename(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'.i','Input/'+dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'.i')
     j = 0
     j_str = index_to_str(j)
     filepath = Path(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'.pvtu')
     while filepath.exists():
         for i_proc in range(dict_algorithm['np_proc']):
            os.rename(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'_'+str(i_proc)+'.vtu','Output/Ite_'+str(dict_algorithm['i_PFDEM'])+'/'+dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'_'+str(i_proc)+'.vtu')
         os.rename(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'.pvtu','Output/Ite_'+str(dict_algorithm['i_PFDEM'])+'/'+dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'.pvtu')
         j = j + 1
         j_str = index_to_str(j)
         filepath = Path(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'.pvtu')

     return index_to_str(j-1)

#-------------------------------------------------------------------------------

def Extract_solute_at_p(dict_sample,ij_p):
    '''
    Extract the value of the solute concentration at a given point.

     Input :
         a sample dictionnary (a dict)
         a coordinate of the point (a tuple of int)
     Output :
         the value of the solute concentration (a float)
    '''
    return dict_sample['solute_M'][-1-ij_p[0]][ij_p[1]]

#-------------------------------------------------------------------------------

def Cosine_Profile(R,r,w):
    '''
    Compute the phase field variable at some point.

    A cosine profile is assumed (see https://mooseframework.inl.gov/source/ics/SmoothCircleIC.html).

    Input :
        the radius R of the grain in the direction (a float)
        the distance r between the current point and the center (a float)
        the width w of the interface (a float)
    Output :
        the value of the phase field variable (a float)
    '''
    #inside the grain
    if r<R-w/2:
        return 1
    #outside the grain
    elif r>R+w/2:
        return 0
    #inside the interface
    else :
        return 0.5*(1 + math.cos(math.pi*(r-R+w/2)/w))

#-------------------------------------------------------------------------------

def error_on_ymax_f(dy,overlap_L,k_L,Force_target) :
    """
    Compute the function f to control the upper wall. It is the difference between the force applied and the target value.

        Input :
            an increment of the upper wall position (a float)
            a list of overlap for contact between grain and upper wall (a list)
            a list of spring for contact between grain and upper wall (a list)
            a confinement force (a float)
        Output :
            the difference between the force applied and the confinement (a float)
    """
    f = Force_target
    for i in range(len(overlap_L)):
        f = f - k_L[i]*(max(overlap_L[i]-dy,0))**(3/2)
    return f

#-------------------------------------------------------------------------------

def error_on_ymax_df(dy,overlap_L,k_L) :
    """
    Compute the derivative function df to control the upper wall (error_on_ymax_f()).

        Input :
            an increment of the upper wall position (a float)
            a list of overlap for contact between grain and upper wall (a list)
            a list of spring for contact between grain and upper wall (a list)
        Output :
            the derivative of error_on_ymax_f() (a float)
    """
    df = 0
    for i in range(len(overlap_L)):
        df = df + 3/2*k_L[i]*(max(overlap_L[i]-dy,0))**(1/2)
    return df

#-------------------------------------------------------------------------------

def Control_y_max_NR(dict_sample,dict_sollicitation):
    """
    Control the upper wall to apply force.

    A Newton-Raphson method is applied to verify the confinement.
        Input :
            a sample dictionnary (a dict)
            a sollicitations dictionnary (a dict)
        Output :
            Nothing, but the sample dictionnary is updated, concerning the upper wall position and force applied (two floats)
    """
    #-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
    #load data needed
    Force_target = dict_sollicitation['Vertical_Confinement_Force']
    #-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.

    F = 0
    overlap_L = []
    k_L = []
    for contact in dict_sample['L_contact_gw']:
        if contact.nature == 'gwy_max':
            F = F + contact.Fwg_n
            overlap_L.append(contact.overlap)
            k_L.append(contact.k)
            #compute force applied, save contact overlap and spring

    if overlap_L != []:
        i_NR = 0
        dy = 0
        ite_criteria = True
        if -0.01*Force_target<error_on_ymax_f(dy,overlap_L,k_L,Force_target) and error_on_ymax_f(dy,overlap_L,k_L,Force_target)<0.01*Force_target:
            ite_criteria = False
        while ite_criteria :
            i_NR = i_NR + 1
            dy = dy - error_on_ymax_f(dy,overlap_L,k_L,Force_target)/error_on_ymax_df(dy,overlap_L,k_L)
            if i_NR > 100:
                ite_criteria = False
            if -0.01*Force_target<error_on_ymax_f(dy,overlap_L,k_L,Force_target) and error_on_ymax_f(dy,overlap_L,k_L,Force_target)<0.01*Force_target:
                ite_criteria = False
        dict_sample['y_box_max'] = dict_sample['y_box_max'] + dy

    else :
        #if there is no contact with the upper wall, the wall is reset
        dict_sample['y_box_max'] = Reset_y_max(dict_sample['L_g'],Force_target)

    for contact in dict_sample['L_contact_gw']:
        if contact.nature == 'gwy_max':
            #reactualisation
            contact.limit = dict_sample['y_box_max']

    #Update dict
    dict_sollicitation['Force_on_upper_wall'] = F

#-------------------------------------------------------------------------------

def Reset_y_max(L_g,Force):
    """
    The upper wall is located as a single contact verify the target value.

        Input :
            the list of temporary grains (a list)
            the confinement force (a float)
        Output :
            the upper wall position (a float)
    """
    print('Reset of the y_max on the upper grain')
    y_max = None
    id_grain_max = None
    for id_grain in range(len(L_g)):
        grain = L_g[id_grain]
        y_max_grain = max(grain.l_border_y)

        if y_max != None and y_max_grain > y_max:
            y_max = y_max_grain
            id_grain_max = id_grain
        elif y_max == None:
            y_max = y_max_grain
            id_grain_max = id_grain

    k = 5*4/3*L_g[id_grain_max].y/(1-L_g[id_grain_max].nu*L_g[id_grain_max].nu)*math.sqrt(L_g[id_grain_max].r_mean)
    y_max = y_max - (Force/k)**(2/3)

    return y_max

#-------------------------------------------------------------------------------

def Interpolate_solute_out_grains(dict_algorithm, dict_sample) :
    """
    For all node of the mesh, if there is solute in one grain it is moved to the nearest node out of the grain.

    A node in multiple grain (contact area) is not considered in a grain a solute can exist.

        Input :
            an algorithm dictionnary (a dict)
            a sample dictionnary (a dict)
        Output :
            Nothing, but the solute map is updated (a ny x nx numpy array)
    """
    #Create maps of different available nodes
    node_available_M = np.array(np.ones((len(dict_sample['y_L']),len(dict_sample['x_L'])),dtype = bool))
    for l in range(len(dict_sample['y_L'])):
        for c in range(len(dict_sample['x_L'])):
            n_grain = 0
            for etai in dict_sample['L_etai']:
                if etai.etai_M[l][c] > 0.5 :
                    n_grain = n_grain + 1
            if n_grain == 1:
                node_available_M[l][c] = False

    #dilatation
    dilated_M = binary_dilation(node_available_M, dict_algorithm['struct_element'])

    #iteration on solute map to see if some solute is in not available position
    for l in range(len(dict_sample['y_L'])):
        for c in range(len(dict_sample['x_L'])):
            if dict_sample['solute_M'][l][c] > 0 and not dilated_M[l][c]:
                solute_moved = False
                size_window = 1
                while not solute_moved :
                    i_window = 0
                    while not solute_moved and i_window <= size_window:
                        n_node_available = 0

                        #Look to move horizontaly and vertically
                        if i_window == 0 :
                            top_available = False
                            down_available = False
                            left_available = False
                            right_available = False
                            #to the top
                            if l - size_window > 0:
                                top_available = dilated_M[l-size_window][c]
                                if dilated_M[l-size_window][c] :
                                    n_node_available = n_node_available + 1
                            #to the down
                            if l + size_window < len(dict_sample['y_L']):
                                down_available = dilated_M[l+size_window][c]
                                if dilated_M[l+size_window][c] :
                                    n_node_available = n_node_available + 1
                            #to the left
                            if c - size_window > 0:
                                left_available = dilated_M[l][c-size_window]
                                if dilated_M[l][c-size_window] :
                                    n_node_available = n_node_available + 1
                            #to the right
                            if c + size_window < len(dict_sample['x_L']):
                                right_available = dilated_M[l][c+size_window]
                                if dilated_M[l][c+size_window] :
                                    n_node_available = n_node_available + 1

                            #move solute if et least one node is available
                            if n_node_available != 0 :
                                #to the top
                                if top_available:
                                    dict_sample['solute_M'][l-size_window][c] = dict_sample['solute_M'][l-size_window][c] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the down
                                if down_available:
                                    dict_sample['solute_M'][l+size_window][c] = dict_sample['solute_M'][l+size_window][c] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the left
                                if left_available:
                                    dict_sample['solute_M'][l][c-size_window] = dict_sample['solute_M'][l][c-size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the right
                                if right_available:
                                    dict_sample['solute_M'][l][c+size_window] = dict_sample['solute_M'][l][c+size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                dict_sample['solute_M'][l][c] = 0
                                solute_moved = True

                        #Look to move diagonally
                        else :
                            top_min_available = False
                            top_max_available = False
                            down_min_available = False
                            down_max_available = False
                            left_min_available = False
                            left_max_available = False
                            right_min_available = False
                            right_max_available = False
                            #to the top
                            if l - size_window > 0:
                                if c - i_window > 0 :
                                    top_min_available = dilated_M[l-size_window][c-i_window]
                                    if dilated_M[l-size_window][c-i_window] :
                                        n_node_available = n_node_available + 1
                                if c + i_window < len(dict_sample['x_L']):
                                    top_max_available = dilated_M[l-size_window][c+i_window]
                                    if dilated_M[l-size_window][c+i_window] :
                                        n_node_available = n_node_available + 1
                            #to the down
                            if l + size_window < len(dict_sample['y_L']):
                                if c - i_window > 0 :
                                    down_min_available = dilated_M[l+size_window][c-i_window]
                                    if dilated_M[l+size_window][c-i_window] :
                                        n_node_available = n_node_available + 1
                                if c + i_window < len(dict_sample['x_L']):
                                    down_max_available = dilated_M[l+size_window][c+i_window]
                                    if dilated_M[l+size_window][c+i_window] :
                                        n_node_available = n_node_available + 1
                            #to the left
                            if c - size_window > 0:
                                if l - i_window > 0 :
                                    left_min_available = dilated_M[l-i_window][c-size_window]
                                    if dilated_M[l-i_window][c-size_window] :
                                        n_node_available = n_node_available + 1
                                if l + i_window < len(dict_sample['y_L']):
                                    left_max_available = dilated_M[l+i_window][c-size_window]
                                    if dilated_M[l+i_window][c-size_window] :
                                        n_node_available = n_node_available + 1
                            #to the right
                            if c + size_window < len(dict_sample['x_L']):
                                if l - i_window > 0 :
                                    right_min_available = dilated_M[l-i_window][c+size_window]
                                    if dilated_M[l-i_window][c+size_window] :
                                        n_node_available = n_node_available + 1
                                if l + i_window < len(dict_sample['y_L']):
                                    right_max_available = dilated_M[l+i_window][c+size_window]
                                    if dilated_M[l+i_window][c+size_window] :
                                        n_node_available = n_node_available + 1

                            #move solute if et least one node is available
                            if n_node_available != 0 :
                                #to the top
                                if top_min_available:
                                    dict_sample['solute_M'][l-size_window][c-i_window] = dict_sample['solute_M'][l-size_window][c-i_window] + dict_sample['solute_M'][l][c]/n_node_available
                                if top_max_available:
                                    dict_sample['solute_M'][l-size_window][c+i_window] = dict_sample['solute_M'][l-size_window][c+i_window] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the down
                                if down_min_available:
                                    dict_sample['solute_M'][l+size_window][c-i_window] = dict_sample['solute_M'][l+size_window][c-i_window] + dict_sample['solute_M'][l][c]/n_node_available
                                if down_max_available:
                                    dict_sample['solute_M'][l+size_window][c+i_window] = dict_sample['solute_M'][l+size_window][c+i_window] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the left
                                if left_min_available:
                                    dict_sample['solute_M'][l-i_window][c-size_window] = dict_sample['solute_M'][l-i_window][c-size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                if left_max_available:
                                    dict_sample['solute_M'][l+i_window][c-size_window] = dict_sample['solute_M'][l+i_window][c-size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the right
                                if right_min_available:
                                    dict_sample['solute_M'][l-i_window][c+size_window] = dict_sample['solute_M'][l-i_window][c+size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                if right_max_available:
                                    dict_sample['solute_M'][l+i_window][c+size_window] = dict_sample['solute_M'][l+i_window][c+size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                dict_sample['solute_M'][l][c] = 0
                                solute_moved = True

                        i_window = i_window + 1
                    size_window = size_window + 1

Sub-modules

Owntools.Compute

@author: Alexandre Sac–Morane alexandre.sac-morane@uclouvain.be
Functions to compute parameters or variables.

Owntools.PFtoDEM_Multi

@author: Alexandre Sac–Morane alexandre.sac-morane@uclouvain.be
Functions to convert PF data into DEM data.

Owntools.Plot

@author: Alexandre Sac–Morane alexandre.sac-morane@uclouvain.be
Functions to plot data.

Owntools.Save

@author: Alexandre Sac–Morane alexandre.sac-morane@uclouvain.be
Functions to save data.

Owntools.Write

@author: Alexandre Sac–Morane alexandre.sac-morane@uclouvain.be
Functions to write .txt or .i files.

Functions

def Control_y_max_NR(dict_sample, dict_sollicitation)

Control the upper wall to apply force.

A Newton-Raphson method is applied to verify the confinement. Input : a sample dictionnary (a dict) a sollicitations dictionnary (a dict) Output : Nothing, but the sample dictionnary is updated, concerning the upper wall position and force applied (two floats)

Expand source code
def Control_y_max_NR(dict_sample,dict_sollicitation):
    """
    Control the upper wall to apply force.

    A Newton-Raphson method is applied to verify the confinement.
        Input :
            a sample dictionnary (a dict)
            a sollicitations dictionnary (a dict)
        Output :
            Nothing, but the sample dictionnary is updated, concerning the upper wall position and force applied (two floats)
    """
    #-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
    #load data needed
    Force_target = dict_sollicitation['Vertical_Confinement_Force']
    #-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.

    F = 0
    overlap_L = []
    k_L = []
    for contact in dict_sample['L_contact_gw']:
        if contact.nature == 'gwy_max':
            F = F + contact.Fwg_n
            overlap_L.append(contact.overlap)
            k_L.append(contact.k)
            #compute force applied, save contact overlap and spring

    if overlap_L != []:
        i_NR = 0
        dy = 0
        ite_criteria = True
        if -0.01*Force_target<error_on_ymax_f(dy,overlap_L,k_L,Force_target) and error_on_ymax_f(dy,overlap_L,k_L,Force_target)<0.01*Force_target:
            ite_criteria = False
        while ite_criteria :
            i_NR = i_NR + 1
            dy = dy - error_on_ymax_f(dy,overlap_L,k_L,Force_target)/error_on_ymax_df(dy,overlap_L,k_L)
            if i_NR > 100:
                ite_criteria = False
            if -0.01*Force_target<error_on_ymax_f(dy,overlap_L,k_L,Force_target) and error_on_ymax_f(dy,overlap_L,k_L,Force_target)<0.01*Force_target:
                ite_criteria = False
        dict_sample['y_box_max'] = dict_sample['y_box_max'] + dy

    else :
        #if there is no contact with the upper wall, the wall is reset
        dict_sample['y_box_max'] = Reset_y_max(dict_sample['L_g'],Force_target)

    for contact in dict_sample['L_contact_gw']:
        if contact.nature == 'gwy_max':
            #reactualisation
            contact.limit = dict_sample['y_box_max']

    #Update dict
    dict_sollicitation['Force_on_upper_wall'] = F
def Cosine_Profile(R, r, w)

Compute the phase field variable at some point.

A cosine profile is assumed (see https://mooseframework.inl.gov/source/ics/SmoothCircleIC.html).

Input : the radius R of the grain in the direction (a float) the distance r between the current point and the center (a float) the width w of the interface (a float) Output : the value of the phase field variable (a float)

Expand source code
def Cosine_Profile(R,r,w):
    '''
    Compute the phase field variable at some point.

    A cosine profile is assumed (see https://mooseframework.inl.gov/source/ics/SmoothCircleIC.html).

    Input :
        the radius R of the grain in the direction (a float)
        the distance r between the current point and the center (a float)
        the width w of the interface (a float)
    Output :
        the value of the phase field variable (a float)
    '''
    #inside the grain
    if r<R-w/2:
        return 1
    #outside the grain
    elif r>R+w/2:
        return 0
    #inside the interface
    else :
        return 0.5*(1 + math.cos(math.pi*(r-R+w/2)/w))
def Extract_solute_at_p(dict_sample, ij_p)

Extract the value of the solute concentration at a given point.

Input : a sample dictionnary (a dict) a coordinate of the point (a tuple of int) Output : the value of the solute concentration (a float)

Expand source code
def Extract_solute_at_p(dict_sample,ij_p):
    '''
    Extract the value of the solute concentration at a given point.

     Input :
         a sample dictionnary (a dict)
         a coordinate of the point (a tuple of int)
     Output :
         the value of the solute concentration (a float)
    '''
    return dict_sample['solute_M'][-1-ij_p[0]][ij_p[1]]
def Interpolate_solute_out_grains(dict_algorithm, dict_sample)

For all node of the mesh, if there is solute in one grain it is moved to the nearest node out of the grain.

A node in multiple grain (contact area) is not considered in a grain a solute can exist.

Input :
    an algorithm dictionnary (a dict)
    a sample dictionnary (a dict)
Output :
    Nothing, but the solute map is updated (a ny x nx numpy array)
Expand source code
def Interpolate_solute_out_grains(dict_algorithm, dict_sample) :
    """
    For all node of the mesh, if there is solute in one grain it is moved to the nearest node out of the grain.

    A node in multiple grain (contact area) is not considered in a grain a solute can exist.

        Input :
            an algorithm dictionnary (a dict)
            a sample dictionnary (a dict)
        Output :
            Nothing, but the solute map is updated (a ny x nx numpy array)
    """
    #Create maps of different available nodes
    node_available_M = np.array(np.ones((len(dict_sample['y_L']),len(dict_sample['x_L'])),dtype = bool))
    for l in range(len(dict_sample['y_L'])):
        for c in range(len(dict_sample['x_L'])):
            n_grain = 0
            for etai in dict_sample['L_etai']:
                if etai.etai_M[l][c] > 0.5 :
                    n_grain = n_grain + 1
            if n_grain == 1:
                node_available_M[l][c] = False

    #dilatation
    dilated_M = binary_dilation(node_available_M, dict_algorithm['struct_element'])

    #iteration on solute map to see if some solute is in not available position
    for l in range(len(dict_sample['y_L'])):
        for c in range(len(dict_sample['x_L'])):
            if dict_sample['solute_M'][l][c] > 0 and not dilated_M[l][c]:
                solute_moved = False
                size_window = 1
                while not solute_moved :
                    i_window = 0
                    while not solute_moved and i_window <= size_window:
                        n_node_available = 0

                        #Look to move horizontaly and vertically
                        if i_window == 0 :
                            top_available = False
                            down_available = False
                            left_available = False
                            right_available = False
                            #to the top
                            if l - size_window > 0:
                                top_available = dilated_M[l-size_window][c]
                                if dilated_M[l-size_window][c] :
                                    n_node_available = n_node_available + 1
                            #to the down
                            if l + size_window < len(dict_sample['y_L']):
                                down_available = dilated_M[l+size_window][c]
                                if dilated_M[l+size_window][c] :
                                    n_node_available = n_node_available + 1
                            #to the left
                            if c - size_window > 0:
                                left_available = dilated_M[l][c-size_window]
                                if dilated_M[l][c-size_window] :
                                    n_node_available = n_node_available + 1
                            #to the right
                            if c + size_window < len(dict_sample['x_L']):
                                right_available = dilated_M[l][c+size_window]
                                if dilated_M[l][c+size_window] :
                                    n_node_available = n_node_available + 1

                            #move solute if et least one node is available
                            if n_node_available != 0 :
                                #to the top
                                if top_available:
                                    dict_sample['solute_M'][l-size_window][c] = dict_sample['solute_M'][l-size_window][c] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the down
                                if down_available:
                                    dict_sample['solute_M'][l+size_window][c] = dict_sample['solute_M'][l+size_window][c] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the left
                                if left_available:
                                    dict_sample['solute_M'][l][c-size_window] = dict_sample['solute_M'][l][c-size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the right
                                if right_available:
                                    dict_sample['solute_M'][l][c+size_window] = dict_sample['solute_M'][l][c+size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                dict_sample['solute_M'][l][c] = 0
                                solute_moved = True

                        #Look to move diagonally
                        else :
                            top_min_available = False
                            top_max_available = False
                            down_min_available = False
                            down_max_available = False
                            left_min_available = False
                            left_max_available = False
                            right_min_available = False
                            right_max_available = False
                            #to the top
                            if l - size_window > 0:
                                if c - i_window > 0 :
                                    top_min_available = dilated_M[l-size_window][c-i_window]
                                    if dilated_M[l-size_window][c-i_window] :
                                        n_node_available = n_node_available + 1
                                if c + i_window < len(dict_sample['x_L']):
                                    top_max_available = dilated_M[l-size_window][c+i_window]
                                    if dilated_M[l-size_window][c+i_window] :
                                        n_node_available = n_node_available + 1
                            #to the down
                            if l + size_window < len(dict_sample['y_L']):
                                if c - i_window > 0 :
                                    down_min_available = dilated_M[l+size_window][c-i_window]
                                    if dilated_M[l+size_window][c-i_window] :
                                        n_node_available = n_node_available + 1
                                if c + i_window < len(dict_sample['x_L']):
                                    down_max_available = dilated_M[l+size_window][c+i_window]
                                    if dilated_M[l+size_window][c+i_window] :
                                        n_node_available = n_node_available + 1
                            #to the left
                            if c - size_window > 0:
                                if l - i_window > 0 :
                                    left_min_available = dilated_M[l-i_window][c-size_window]
                                    if dilated_M[l-i_window][c-size_window] :
                                        n_node_available = n_node_available + 1
                                if l + i_window < len(dict_sample['y_L']):
                                    left_max_available = dilated_M[l+i_window][c-size_window]
                                    if dilated_M[l+i_window][c-size_window] :
                                        n_node_available = n_node_available + 1
                            #to the right
                            if c + size_window < len(dict_sample['x_L']):
                                if l - i_window > 0 :
                                    right_min_available = dilated_M[l-i_window][c+size_window]
                                    if dilated_M[l-i_window][c+size_window] :
                                        n_node_available = n_node_available + 1
                                if l + i_window < len(dict_sample['y_L']):
                                    right_max_available = dilated_M[l+i_window][c+size_window]
                                    if dilated_M[l+i_window][c+size_window] :
                                        n_node_available = n_node_available + 1

                            #move solute if et least one node is available
                            if n_node_available != 0 :
                                #to the top
                                if top_min_available:
                                    dict_sample['solute_M'][l-size_window][c-i_window] = dict_sample['solute_M'][l-size_window][c-i_window] + dict_sample['solute_M'][l][c]/n_node_available
                                if top_max_available:
                                    dict_sample['solute_M'][l-size_window][c+i_window] = dict_sample['solute_M'][l-size_window][c+i_window] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the down
                                if down_min_available:
                                    dict_sample['solute_M'][l+size_window][c-i_window] = dict_sample['solute_M'][l+size_window][c-i_window] + dict_sample['solute_M'][l][c]/n_node_available
                                if down_max_available:
                                    dict_sample['solute_M'][l+size_window][c+i_window] = dict_sample['solute_M'][l+size_window][c+i_window] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the left
                                if left_min_available:
                                    dict_sample['solute_M'][l-i_window][c-size_window] = dict_sample['solute_M'][l-i_window][c-size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                if left_max_available:
                                    dict_sample['solute_M'][l+i_window][c-size_window] = dict_sample['solute_M'][l+i_window][c-size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                #to the right
                                if right_min_available:
                                    dict_sample['solute_M'][l-i_window][c+size_window] = dict_sample['solute_M'][l-i_window][c+size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                if right_max_available:
                                    dict_sample['solute_M'][l+i_window][c+size_window] = dict_sample['solute_M'][l+i_window][c+size_window] + dict_sample['solute_M'][l][c]/n_node_available
                                dict_sample['solute_M'][l][c] = 0
                                solute_moved = True

                        i_window = i_window + 1
                    size_window = size_window + 1
def Reset_y_max(L_g, Force)

The upper wall is located as a single contact verify the target value.

Input :
    the list of temporary grains (a list)
    the confinement force (a float)
Output :
    the upper wall position (a float)
Expand source code
def Reset_y_max(L_g,Force):
    """
    The upper wall is located as a single contact verify the target value.

        Input :
            the list of temporary grains (a list)
            the confinement force (a float)
        Output :
            the upper wall position (a float)
    """
    print('Reset of the y_max on the upper grain')
    y_max = None
    id_grain_max = None
    for id_grain in range(len(L_g)):
        grain = L_g[id_grain]
        y_max_grain = max(grain.l_border_y)

        if y_max != None and y_max_grain > y_max:
            y_max = y_max_grain
            id_grain_max = id_grain
        elif y_max == None:
            y_max = y_max_grain
            id_grain_max = id_grain

    k = 5*4/3*L_g[id_grain_max].y/(1-L_g[id_grain_max].nu*L_g[id_grain_max].nu)*math.sqrt(L_g[id_grain_max].r_mean)
    y_max = y_max - (Force/k)**(2/3)

    return y_max
def Sort_Files(dict_algorithm)

Sort files generated by MOOSE to different directories

Input : an algorithm dictionnary (a dict) Output : Nothing but files are sorted

Expand source code
def Sort_Files(dict_algorithm):
     '''
     Sort files generated by MOOSE to different directories

        Input :
            an algorithm dictionnary (a dict)
        Output :
            Nothing but files are sorted
     '''

     os.rename(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_out.e','Output/'+dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_out.e')
     os.rename(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'.i','Input/'+dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'.i')
     j = 0
     j_str = index_to_str(j)
     filepath = Path(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'.pvtu')
     while filepath.exists():
         for i_proc in range(dict_algorithm['np_proc']):
            os.rename(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'_'+str(i_proc)+'.vtu','Output/Ite_'+str(dict_algorithm['i_PFDEM'])+'/'+dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'_'+str(i_proc)+'.vtu')
         os.rename(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'.pvtu','Output/Ite_'+str(dict_algorithm['i_PFDEM'])+'/'+dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'.pvtu')
         j = j + 1
         j_str = index_to_str(j)
         filepath = Path(dict_algorithm['namefile']+'_'+str(dict_algorithm['i_PFDEM'])+'_other_'+j_str+'.pvtu')

     return index_to_str(j-1)
def error_on_ymax_df(dy, overlap_L, k_L)

Compute the derivative function df to control the upper wall (error_on_ymax_f()).

Input :
    an increment of the upper wall position (a float)
    a list of overlap for contact between grain and upper wall (a list)
    a list of spring for contact between grain and upper wall (a list)
Output :
    the derivative of error_on_ymax_f() (a float)
Expand source code
def error_on_ymax_df(dy,overlap_L,k_L) :
    """
    Compute the derivative function df to control the upper wall (error_on_ymax_f()).

        Input :
            an increment of the upper wall position (a float)
            a list of overlap for contact between grain and upper wall (a list)
            a list of spring for contact between grain and upper wall (a list)
        Output :
            the derivative of error_on_ymax_f() (a float)
    """
    df = 0
    for i in range(len(overlap_L)):
        df = df + 3/2*k_L[i]*(max(overlap_L[i]-dy,0))**(1/2)
    return df
def error_on_ymax_f(dy, overlap_L, k_L, Force_target)

Compute the function f to control the upper wall. It is the difference between the force applied and the target value.

Input :
    an increment of the upper wall position (a float)
    a list of overlap for contact between grain and upper wall (a list)
    a list of spring for contact between grain and upper wall (a list)
    a confinement force (a float)
Output :
    the difference between the force applied and the confinement (a float)
Expand source code
def error_on_ymax_f(dy,overlap_L,k_L,Force_target) :
    """
    Compute the function f to control the upper wall. It is the difference between the force applied and the target value.

        Input :
            an increment of the upper wall position (a float)
            a list of overlap for contact between grain and upper wall (a list)
            a list of spring for contact between grain and upper wall (a list)
            a confinement force (a float)
        Output :
            the difference between the force applied and the confinement (a float)
    """
    f = Force_target
    for i in range(len(overlap_L)):
        f = f - k_L[i]*(max(overlap_L[i]-dy,0))**(3/2)
    return f
def index_to_str(j)

An integer is converted to a float with 3 components

Input : a number (a float) Output : a string with 3 components (a string)

Expand source code
def index_to_str(j):
  '''
  An integer is converted to a float with 3 components

    Input :
        a number (a float)
    Output :
        a string with 3 components (a string)
  '''
  if j < 10:
      j_str = '00'+str(j)
  elif 10 <= j and j < 100:
      j_str = '0'+str(j)
  else :
      j_str = str(j)
  return j_str