Avoiding CPU branching on leapfrog simulation









up vote
0
down vote

favorite












I have written a computational simulation that accepts some optional parameters (as boundary conditions). As shown in the code below



def leapfrog(dx, dt, u_0, v_0, U, V, u_l=None, u_r=None, v_l=None, v_r=None, 
n_max=None, **kwargs):
"""Every call returns a timestep of leapfrog iteration given:
dx: Spatial step
dt: Time step
u0: Initial condition of regular grid
v0: Initial condition of staggered grid
U: Operator to apply over the regular grid
V: Operator to apply over staggered grid
u_l: left boundary condition to regular grid
u_r: right boundary condition to regular grid
v_l: left boundary condition to staggered grid
v_r: right boundary conditiion to staggered grid
n_max: If nmax is given, stops after n_max iterations (> 2)

For every call returns another timestep

"""
# Initial condition
yield u_0, v_0

# First iteration
u = u_0 - (dt/dx) * (V @ v_0)
if u_l is not None:
u[:len(u_l)] = u_l
if u_r is not None:
u[-len(u_r):] = u_r

v = v_0 - (dt/dx) * (U @ u_0)
if v_l is not None:
v[:len(v_l)] = v_l
if v_r is not None:
v[-len(v_r):] = v_r
yield u, v

# All other iterations
for n in itertools.count(start=2, step=1):
u = u - (dt/dx) * (V @ v)
if u_l is not None:
u[:u_l.size] = u_l
if u_r is not None:
u[-u_r.size:] = u_r

v = v - (dt/dx) * (U @ u)
if v_l is not None:
v[:v_l.size] = v_l
if v_r is not None:
v[-v_r.size:] = v_r

if n_max is not None and n >= n_max:
break

yield u,v


While the code works fine, it for sure triggers CPU branching since I check if I added boundary condition in main and secondary grid (u and v) at left and right (_l and _r), for example, u_l means left boundary condition in main grid.



u_l, u_r, v_l and v_r are numpy arrays like np.array([0]). I need to add dimension, otherwise (if a scaler) it has no len and also that makes things more uniform.



In other hands sometimes I do not want to add boundary conditions, in these cases I use the if statement to catch it.



My question is, is there any way to avoid the branching (and all ifs)?



Of course, I could create 'specialized' functions with and without boundary condition (in main and secondary grids), but I'm looking a more generic approach.



Also, any other hints to improve the code are very welcome.










share|improve this question



























    up vote
    0
    down vote

    favorite












    I have written a computational simulation that accepts some optional parameters (as boundary conditions). As shown in the code below



    def leapfrog(dx, dt, u_0, v_0, U, V, u_l=None, u_r=None, v_l=None, v_r=None, 
    n_max=None, **kwargs):
    """Every call returns a timestep of leapfrog iteration given:
    dx: Spatial step
    dt: Time step
    u0: Initial condition of regular grid
    v0: Initial condition of staggered grid
    U: Operator to apply over the regular grid
    V: Operator to apply over staggered grid
    u_l: left boundary condition to regular grid
    u_r: right boundary condition to regular grid
    v_l: left boundary condition to staggered grid
    v_r: right boundary conditiion to staggered grid
    n_max: If nmax is given, stops after n_max iterations (> 2)

    For every call returns another timestep

    """
    # Initial condition
    yield u_0, v_0

    # First iteration
    u = u_0 - (dt/dx) * (V @ v_0)
    if u_l is not None:
    u[:len(u_l)] = u_l
    if u_r is not None:
    u[-len(u_r):] = u_r

    v = v_0 - (dt/dx) * (U @ u_0)
    if v_l is not None:
    v[:len(v_l)] = v_l
    if v_r is not None:
    v[-len(v_r):] = v_r
    yield u, v

    # All other iterations
    for n in itertools.count(start=2, step=1):
    u = u - (dt/dx) * (V @ v)
    if u_l is not None:
    u[:u_l.size] = u_l
    if u_r is not None:
    u[-u_r.size:] = u_r

    v = v - (dt/dx) * (U @ u)
    if v_l is not None:
    v[:v_l.size] = v_l
    if v_r is not None:
    v[-v_r.size:] = v_r

    if n_max is not None and n >= n_max:
    break

    yield u,v


    While the code works fine, it for sure triggers CPU branching since I check if I added boundary condition in main and secondary grid (u and v) at left and right (_l and _r), for example, u_l means left boundary condition in main grid.



    u_l, u_r, v_l and v_r are numpy arrays like np.array([0]). I need to add dimension, otherwise (if a scaler) it has no len and also that makes things more uniform.



    In other hands sometimes I do not want to add boundary conditions, in these cases I use the if statement to catch it.



    My question is, is there any way to avoid the branching (and all ifs)?



    Of course, I could create 'specialized' functions with and without boundary condition (in main and secondary grids), but I'm looking a more generic approach.



    Also, any other hints to improve the code are very welcome.










    share|improve this question

























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I have written a computational simulation that accepts some optional parameters (as boundary conditions). As shown in the code below



      def leapfrog(dx, dt, u_0, v_0, U, V, u_l=None, u_r=None, v_l=None, v_r=None, 
      n_max=None, **kwargs):
      """Every call returns a timestep of leapfrog iteration given:
      dx: Spatial step
      dt: Time step
      u0: Initial condition of regular grid
      v0: Initial condition of staggered grid
      U: Operator to apply over the regular grid
      V: Operator to apply over staggered grid
      u_l: left boundary condition to regular grid
      u_r: right boundary condition to regular grid
      v_l: left boundary condition to staggered grid
      v_r: right boundary conditiion to staggered grid
      n_max: If nmax is given, stops after n_max iterations (> 2)

      For every call returns another timestep

      """
      # Initial condition
      yield u_0, v_0

      # First iteration
      u = u_0 - (dt/dx) * (V @ v_0)
      if u_l is not None:
      u[:len(u_l)] = u_l
      if u_r is not None:
      u[-len(u_r):] = u_r

      v = v_0 - (dt/dx) * (U @ u_0)
      if v_l is not None:
      v[:len(v_l)] = v_l
      if v_r is not None:
      v[-len(v_r):] = v_r
      yield u, v

      # All other iterations
      for n in itertools.count(start=2, step=1):
      u = u - (dt/dx) * (V @ v)
      if u_l is not None:
      u[:u_l.size] = u_l
      if u_r is not None:
      u[-u_r.size:] = u_r

      v = v - (dt/dx) * (U @ u)
      if v_l is not None:
      v[:v_l.size] = v_l
      if v_r is not None:
      v[-v_r.size:] = v_r

      if n_max is not None and n >= n_max:
      break

      yield u,v


      While the code works fine, it for sure triggers CPU branching since I check if I added boundary condition in main and secondary grid (u and v) at left and right (_l and _r), for example, u_l means left boundary condition in main grid.



      u_l, u_r, v_l and v_r are numpy arrays like np.array([0]). I need to add dimension, otherwise (if a scaler) it has no len and also that makes things more uniform.



      In other hands sometimes I do not want to add boundary conditions, in these cases I use the if statement to catch it.



      My question is, is there any way to avoid the branching (and all ifs)?



      Of course, I could create 'specialized' functions with and without boundary condition (in main and secondary grids), but I'm looking a more generic approach.



      Also, any other hints to improve the code are very welcome.










      share|improve this question















      I have written a computational simulation that accepts some optional parameters (as boundary conditions). As shown in the code below



      def leapfrog(dx, dt, u_0, v_0, U, V, u_l=None, u_r=None, v_l=None, v_r=None, 
      n_max=None, **kwargs):
      """Every call returns a timestep of leapfrog iteration given:
      dx: Spatial step
      dt: Time step
      u0: Initial condition of regular grid
      v0: Initial condition of staggered grid
      U: Operator to apply over the regular grid
      V: Operator to apply over staggered grid
      u_l: left boundary condition to regular grid
      u_r: right boundary condition to regular grid
      v_l: left boundary condition to staggered grid
      v_r: right boundary conditiion to staggered grid
      n_max: If nmax is given, stops after n_max iterations (> 2)

      For every call returns another timestep

      """
      # Initial condition
      yield u_0, v_0

      # First iteration
      u = u_0 - (dt/dx) * (V @ v_0)
      if u_l is not None:
      u[:len(u_l)] = u_l
      if u_r is not None:
      u[-len(u_r):] = u_r

      v = v_0 - (dt/dx) * (U @ u_0)
      if v_l is not None:
      v[:len(v_l)] = v_l
      if v_r is not None:
      v[-len(v_r):] = v_r
      yield u, v

      # All other iterations
      for n in itertools.count(start=2, step=1):
      u = u - (dt/dx) * (V @ v)
      if u_l is not None:
      u[:u_l.size] = u_l
      if u_r is not None:
      u[-u_r.size:] = u_r

      v = v - (dt/dx) * (U @ u)
      if v_l is not None:
      v[:v_l.size] = v_l
      if v_r is not None:
      v[-v_r.size:] = v_r

      if n_max is not None and n >= n_max:
      break

      yield u,v


      While the code works fine, it for sure triggers CPU branching since I check if I added boundary condition in main and secondary grid (u and v) at left and right (_l and _r), for example, u_l means left boundary condition in main grid.



      u_l, u_r, v_l and v_r are numpy arrays like np.array([0]). I need to add dimension, otherwise (if a scaler) it has no len and also that makes things more uniform.



      In other hands sometimes I do not want to add boundary conditions, in these cases I use the if statement to catch it.



      My question is, is there any way to avoid the branching (and all ifs)?



      Of course, I could create 'specialized' functions with and without boundary condition (in main and secondary grids), but I'm looking a more generic approach.



      Also, any other hints to improve the code are very welcome.







      python-3.x numerical-methods branch-prediction






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 9 at 15:27









      Elham Esmaeeli

      655




      655










      asked Nov 9 at 15:13









      Lin

      417214




      417214



























          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53228388%2favoiding-cpu-branching-on-leapfrog-simulation%23new-answer', 'question_page');

          );

          Post as a guest



































          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes















           

          draft saved


          draft discarded















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53228388%2favoiding-cpu-branching-on-leapfrog-simulation%23new-answer', 'question_page');

          );

          Post as a guest














































































          Popular posts from this blog

          Darth Vader #20

          How to how show current date and time by default on contact form 7 in WordPress without taking input from user in datetimepicker

          Ondo