示例#1
0
def draglift(simulations,
             d_cylinder=0.1,
             u_0=1.0,
             flow_dir='y',
             t_start=-1,
             sortby='dx'):
    """
    Compute mean drag coefficient, rms lift coefficient, and Strouhal number
    for flow past a circular cylinder.
    If the flow is steady, only drag and lift coefficients are computed.

    Call signature:
      draglift(simulations)

    Keyword arguments:

    *simulations*
      array of simulation names to be included in the computations

    *d_cylinder*:
      diameter of the cylinder

    *u_0*
      velocity at the inlet

    *flow_dir*:
      direction of the flow

    *t_start*
      time to start the drag computations from
      should be where the a steady vortex shedding has developed

    *sortby*
      property to sort the arrays by
      typical choices for parametric studies are grid size, length of domain, etc.

    Returns
      three arrays: mean C_D, rms C_L, St
    """
    from pencilnew import sim

    # Find directories to include in accuracy assessment
    sims = []
    for simulation in simulations:
        sims.append(sim.get(simulation, quiet=True))

    # Sort simulations
    sims = sim.sort(sims, sortby, reverse=True)

    dragliftst = np.empty([len(simulations), 4])
    for i, thissim in enumerate(sims):
        dragliftst[i, 0] = thissim.get_value(sortby)
        dragliftst[i, 1:] = compute_drag(thissim.get_ts(), d_cylinder, u_0,
                                         flow_dir, t_start)

    return dragliftst
示例#2
0
def draglift(simulations, sortby='dx', **kwargs):
    """
    Compute mean drag coefficient, rms lift coefficient, and Strouhal number
    for flow past a circular cylinder.
    If the flow is steady, only drag and lift coefficients are computed.

    Call signature:
      draglift(simulations, d_cylinder=0.1, u_0=1.0, flow_dir='y', 
               t_start=-1, sortby='dx'):

    Keyword arguments:

    *simulations*
      array of simulation names to be included in the computations

    *d_cylinder*:
      diameter of the cylinder

    *u_0*
      velocity at the inlet

    *flow_dir*:
      direction of the flow

    *t_start*
      time to start the drag computations from
      should be where the a steady vortex shedding has developed

    *sortby*
      property to sort the arrays by
      typical choices for parametric studies are grid size, length of domain, etc.

    Returns
      object with information: sim-name, drag (mean), lift (rms), and st (non-dim shedding frequency)
    """
    sims = []
    for simulation in simulations:
        sims.append(sim.get(simulation, quiet=True))

    # Sort simulations
    sims = sim.sort(sims, sortby, reverse=True)

    draglift_tmp = []
    for i, thissim in enumerate(sims):
        draglift_tmp.append(Draglift())
        draglift_tmp[i].set_name(thissim)
        draglift_tmp[i].compute(thissim, **kwargs)

    return draglift_tmp
示例#3
0
def draglift(simulations, sortby='dx', **kwargs):
    """
    Compute mean drag coefficient, rms lift coefficient, and Strouhal number
    for flow past a circular cylinder.
    If the flow is steady, only drag and lift coefficients are computed.

    Call signature:
      draglift(simulations, d_cylinder=0.1, u_0=1.0, flow_dir='y', 
               t_start=-1, sortby='dx'):

    Keyword arguments:

    *simulations*
      array of simulation names to be included in the computations

    *d_cylinder*:
      diameter of the cylinder

    *u_0*
      velocity at the inlet

    *flow_dir*:
      direction of the flow

    *t_start*
      time to start the drag computations from
      should be where the a steady vortex shedding has developed

    *sortby*
      property to sort the arrays by
      typical choices for parametric studies are grid size, length of domain, etc.

    Returns
      object with information: sim-name, drag (mean), lift (rms), and st (non-dim shedding frequency)
    """
    sims = []
    for simulation in simulations:
        sims.append(sim.get(simulation,quiet=True))

    # Sort simulations
    sims = sim.sort(sims,sortby,reverse=True)

    draglift_tmp = []
    for i,thissim in enumerate(sims):
        draglift_tmp.append(Draglift())
        draglift_tmp[i].set_name(thissim)
        draglift_tmp[i].compute(thissim, **kwargs)

    return draglift_tmp
示例#4
0
def twonorm_accuracy(simulations,
                     field='ux',
                     strip=0,
                     varfile='ogvar.dat',
                     direction='x',
                     noerr=True):
    """
    Assessment of accuracy of simulation:
    Computes the two-norm error of all available simulation, where the simulation
    with the maximum amount of grid points is used as the correct/reference solution.
    E.g., for runs with grid points assessment of accuracy of x-component of velocity
    along the y-direction, for runs with grid points nxgrid = n, 2n, 4n, 8n, compute

    || u_n - u_0 || = dy \sum\limits_{n=0}^n (sqrt(u_n(x_n)-u_0(x_8n)))
    
    for all runs (except for the 8n case, used as reference).

    Requires that the runs have matching grids, that is, grid refined by a factor of 2m,
    and grids adjusted so that the grid point overlap (needs ofset if periodic BC is used).

    call signature:
      twonorm_accuracy(simulations)

    Keyword arguments:

    *simulations*
      array of simulation names to be included in the computations

    *field*
      variable used in accuracy assessment

    *strip*:
      index for strip along coordinate 

    *varfile*:
      name of varfile to read from each sim

    *direction*:
      compute two-norm along 'x' or 'y' direction

    *noerr*:
      set to false if you want to return an array of maximum error along strip, in 
      addition to the two-norm

    Returns
      array of two-norms where the larges array is used as base 
    """

    import numpy as np
    import os as os
    from pencilnew import read
    from pencilnew import sim

    # Find directories to include in accuracy assessment
    sims = []
    for simulation in simulations:
        sims.append(sim.get(simulation, quiet=True))

    # Sort runs by size of grid spacing
    if (direction == 'x' or direction == 'r'):
        sims = sim.sort(sims, 'dx', reverse=True)
    elif (direction == 'y' or direction == 'th'):
        sims = sim.sort(sims, 'dy', reverse=True)

    # From this point we only need the varfile to compute accuracy
    # Need to update dim to ogdim for reading of ogvar to be done
    # correctly from simulation object
    for i, thissim in enumerate(sims):
        sims[i].dim = read.ogdim(datadir=thissim.datadir)
        sims[i] = read.ogvar(sim=thissim, trimall=True)

    # Check that increase in size is correct for use in two-norm calculation
    nsims = len(sims)
    nx_min = sims[0].r.size
    ny_min = sims[0].th.size
    for thissim in sims:
        if ((thissim.r.size - 1) % (nx_min - 1) != 0):
            print('ERROR: Incorrect size in r-dir')
            print('sims.r', thissim.r.size)
            return False

        if (thissim.th.size % ny_min != 0):
            print('ERROR: Incorrect size in th-dir')
            return False

    # Now we are sure that first coordinate of r and th are the same for all runs
    # Can compute the two-norms for increasing sizes. Use largest size as normalization of error
    twonorms = np.zeros(nsims - 1)
    maxerrs = np.zeros(nsims - 1)
    if (direction == 'x' or direction == 'r'):
        dh = sims[0].dx
        n2_factor = int(dh / sims[-1].dx)
    elif (direction == 'y' or direction == 'th'):
        dh = sims[0].dy
        n2_factor = int(dh / sims[-1].dy)

    attribute = getattr(sims[-1], field)
    if (field == 'ux' or field == 'uy'):
        u2 = attribute[0::n2_factor, 0::n2_factor]
    else:
        u2 = attribute[0, 0::n2_factor, 0::n2_factor]

    strip = int(strip)
    i = 0
    for thissim in sims[:-1]:
        if (direction == 'x' or direction == 'r'):
            n2_factor = int(dh / thissim.dx)
        elif (direction == 'y' or direction == 'th'):
            n2_factor = int(dh / thissim.dy)
        attribute = getattr(thissim, field)
        if (field == 'ux' or field == 'uy'):
            u1 = attribute[0::n2_factor, 0::n2_factor]
        else:
            u1 = attribute[0, 0::n2_factor, 0::n2_factor]
        if (direction == 'x' or direction == 'r'):
            twonorms[i] = (twonorm(u1[:, strip], u2[:, strip], dh))
            maxerrs[i] = (maxerror(u1[:, strip], u2[:, strip]))
        elif (direction == 'y' or direction == 'th'):
            twonorms[i] = (twonorm(u1[strip, :], u2[strip, :], dh))
            maxerrs[i] = (maxerror(u1[strip, :], u2[strip, :]))
        i = i + 1

    print('Two-norm computed for field:', field, ', along strip:', strip)
    if (direction == 'x'):
        print('Along x-direction')
    elif (direction == 'r'):
        print('Along r-direction')
    elif (direction == 'y'):
        print('Along y-direction')
    elif (direction == 'th'):
        print('Along th-direction')

    if not noerr:
        return twonorms, maxerrs
    else:
        return twonorms
示例#5
0
def twonorm_accuracy1D(simulations, field='ur', strip=1, direction='r', varfile='ogvar.dat',noerr=True, quiet=True):
    """
    Assessment of accuracy of simulation:
    Computes the two-norm error of all available simulation, where the simulation
    with the maximum amount of grid points is used as the correct/reference solution.
    E.g., for runs with grid points assessment of accuracy of x-component of velocity
    along the y-direction, for runs with grid points nxgrid = n, 2n, 4n, 8n, compute

    || u_n - u_0 || = dy \sum\limits_{n=0}^n (sqrt(u_n(x_n)-u_0(x_8n)))
    
    for all runs (except for the 8n case, used as reference).

    Requires that the runs have matching grids, that is, grid refined by a factor of 2m,
    and grids adjusted so that the grid point overlap (needs ofset if periodic BC is used).

    call signature:
      twonorm_accuracy(simulations)

    Keyword arguments:

    *simulations*
      array of simulation names to be included in the computations

    *field*
      variable used in accuracy assessment

    *varfile*:
      name of varfile to read from each sim

    *noerr*:
      set to false if you want to return an array of maximum error along strip, in 
      addition to the two-norm

    Returns
      array of two-norms where the larges array is used as base 
    """

    import numpy as np
    import os as os
    from pencilnew import read
    from pencilnew import sim

    # Find directories to include in accuracy assessment
    sims = []
    for simulation in simulations:
        sims.append(sim.get(simulation,quiet=True))

    # Sort runs by size of grid spacing
    sims = sim.sort(sims,'dx',reverse=True)

    # From this point we only need the varfile to compute accuracy
    # Need to update dim to ogdim for reading of ogvar to be done
    # correctly from simulation object
    for i,thissim in enumerate(sims):
        sims[i].dim = read.ogdim(datadir=thissim.datadir)
        sims[i] = read.ogvar(sim=thissim,trimall=True,varfile=varfile)

    # Check that increase in size is correct for use in two-norm calculation
    nsims = len(sims)
    nx_min = sims[0].r.size
    ny_min = sims[0].th.size
    for thissim in sims:
        if((thissim.r.size-1)%(nx_min-1) != 0):
            print('ERROR: Incorrect size in r-dir')
            print('sims.r',thissim.r.size)
            print('nx_min',nx_min)
            return False

        if(thissim.th.size%ny_min != 0):
            print('ERROR: Incorrect size in th-dir')
            return False

    # Check that all var-files are for the same time
    t = sims[0].t
    for thissim in sims:
        if thissim.t != t:
            print('WARNING: Incorrect time for one or more simulations')

    # Now we are sure that first coordinate of r and th are the same for all runs
    # Can compute the two-norms for increasing sizes. Use largest size as normalization of error
    twonorms = np.zeros(nsims-1)
    maxerrs = np.zeros(nsims-1)

    # Compute array of factor used to jump indices when comparing two arrays of size N and 2N etc.
    # Usually n2_fac = [8, 4, 2] or similar
    n2_fac = np.empty(nsims-1)
    for i,thissim in enumerate(sims[:-1]):
        n2_fac[i]=thissim.dx/sims[-1].dx

    u2 = getattr(sims[-1],field)
    if not(field=='ux' or field=='uy'):
        u2 = u2[0,:,:]

    for i,thissim in enumerate(sims[:-1]):
        u1 = getattr(thissim,field)
        if not(field=='ux' or field=='uy'):
            u1 = u1[0,:,:]
        
        dr=np.empty(thissim.r.size)
        dr[0:-1] = thissim.r[1:]-thissim.r[0:-1]
        dr[-1]=dr[-2]
        dth = thissim.dy
        twonorms[i]=0.
        n2=n2_fac[i]
        if(direction=='r'):
            r=sims[0].r[strip]
            j=int(strip*sims[0].dx/thissim.dx)
            for k in range(thissim.th.size):
                twonorms[i]=twonorms[i]+dth*r*(u1[k,j]-u2[int(k*n2),int(j*n2)])**2
        elif(direction=='th'):
            k=int(strip*sims[0].dx/thissim.dx)
            for j in range(thissim.r.size):
                twonorms[i]=twonorms[i]+dr[j]*(u1[k,j]-u2[int(k*n2),int(j*n2)])**2
        else:
            print('ERROR: Invalid direction chosen')
            return False

        twonorms[i] = np.sqrt(twonorms[i])

    if not noerr:
        return twonorms, maxerrs
    else:
        return twonorms
示例#6
0
def twonorm_accuracy(simulations, field='ux', strip=0, var_file='ogvar.dat',direction='x',noerr=True, quiet=True):
    """
    Assessment of accuracy of simulation:
    Computes the two-norm error of all available simulation, where the simulation
    with the maximum amount of grid points is used as the correct/reference solution.
    E.g., for runs with grid points assessment of accuracy of x-component of velocity
    along the y-direction, for runs with grid points nxgrid = n, 2n, 4n, 8n, compute

    || u_n - u_0 || = dy \sum\limits_{n=0}^n (sqrt(u_n(x_n)-u_0(x_8n)))
    
    for all runs (except for the 8n case, used as reference).

    Requires that the runs have matching grids, that is, grid refined by a factor of 2m,
    and grids adjusted so that the grid point overlap (needs ofset if periodic BC is used).

    call signature:
      twonorm_accuracy(simulations)

    Keyword arguments:

    *simulations*
      array of simulation names to be included in the computations

    *field*
      variable used in accuracy assessment

    *strip*:
      index for strip along coordinate 

    *var_file*:
      name of varfile to read from each sim

    *direction*:
      compute two-norm along 'x' or 'y' direction

    *noerr*:
      set to false if you want to return an array of maximum error along strip, in 
      addition to the two-norm

    Returns
      array of two-norms where the larges array is used as base 
    """

    import numpy as np
    import os as os
    from pencilnew import read
    from pencilnew import sim

    # Find directories to include in accuracy assessment
    sims = []
    for simulation in simulations:
        sims.append(sim.get(simulation,quiet=True))

    # Sort runs by size of grid spacing
    if(direction=='x' or direction=='r'):
        sims = sim.sort(sims,'nx',reverse=False)
    elif(direction=='y' or direction=='th'):
        sims = sim.sort(sims,'ny',reverse=False)

    # From this point we only need the varfile to compute accuracy
    # Need to update dim to ogdim for reading of ogvar to be done
    # correctly from simulation object
    for i,thissim in enumerate(sims):
        sims[i].dim = read.ogdim(datadir=thissim.datadir)
        sims[i] = read.ogvar(sim=thissim,trimall=True,var_file=var_file)

    # Check that increase in size is correct for use in two-norm calculation
    nsims = len(sims)
    nx_min = sims[0].r.size
    ny_min = sims[0].th.size
    for thissim in sims:
        if((thissim.r.size-1)%(nx_min-1) != 0):
            print('ERROR: Incorrect size in r-dir')
            print('sims.r',thissim.r.size)
            print('nx_min',nx_min)
            return False

        if(thissim.th.size%ny_min != 0):
            print('ERROR: Incorrect size in th-dir')
            return False

    # Check that all var-files are for the same time
    t = sims[0].t
    for thissim in sims:
        if thissim.t != t:
            print('WARNING: Incorrect time for one or more simulations')

    # Now we are sure that first coordinate of r and th are the same for all runs
    # Can compute the two-norms for increasing sizes. Use largest size as normalization of error
    twonorms = np.zeros(nsims-1)
    maxerrs = np.zeros(nsims-1)
    if(direction=='x' or direction=='r'):
        dh = sims[0].dx
        n2_factor = int(dh/sims[-1].dx)
    elif(direction=='y' or direction=='th'):
        dh = sims[0].dy
        n2_factor = int(dh/sims[-1].dy)

    attribute = getattr(sims[-1],field)
    if(field=='ux' or field=='uy'):
        u2 = attribute[0::n2_factor,0::n2_factor]
    else:
        u2 = attribute[0,0::n2_factor,0::n2_factor]

    strip=int(strip)
    if(direction=='x' or direction=='r'):
        dh = sims[-1].dx
        dx_max = sims[0].dx
        n2_factor = int(thissim.dx/dh)
         #for i,thissim in enumerate(sims[:-1]):
         #    strips[i]=int(thissim.dx/dx_max*strip)
         #n1_factor = int(sims[0].dx/sims[-1].dx)
    elif(direction=='y' or direction=='th'):
        dh = sims[-1].dy
        dx_max = sims[0].dy
         #for i,thissim in enumerate(sims[:-1]):
         #    strips[i]=int(thissim.dy/dx_max*strip)
         #n1_factor = int(sims[0].dx/sims[-1].dy)
 
    attribute = getattr(sims[-1],field)
 #    if(field=='ux' or field=='uy'):
 #        u2 = attribute[0::n2_factor,0::n2_factor]
 #    else:
 #        u2 = attribute[0,0::n2_factor,0::n2_factor]
    j=1
    for i, thissim in enumerate(sims[:-1]):
        n1_factor = 1
        if(direction=='x' or direction=='r'):
            n2_factor = int(thissim.dx/dh)
        elif(direction=='y' or direction=='th'):
            n2_factor = int(thissim.dy/dh)
 
        u1 = getattr(thissim,field)
        if(field=='ux' or field=='uy'):
            u2 = attribute[0::n2_factor,0::n2_factor]
            #u1 = u1[0::n1_factor]
        else:
            u2 = attribute[0,0::n2_factor,0::n2_factor]
            u1 = u1[0,:,:]#0::n1_factor,:]
            #u1 = u1[0,0::n1_factor,:]
 
 
        radius_l=sims[-1].r[0::n2_factor]
        if(direction=='x' or direction=='r'):
            twonorms[i] = (twonorm(u1[:,strip*j],u2[:,strip*j],thissim.dy*sims[0].r[strip]))
            maxerrs[i] = (maxerror(u1[:,strip*j],u2[:,strip*j]))
        elif(direction=='y' or direction=='th'):
            twonorms[i] = (twonorm(u1[strip*j,:],u2[strip*j,:],thissim.dx))
            maxerrs[i] = (maxerror(u1[strip*j,:],u2[strip*j,:]))
        j=j*2

#        n1_factor = 1
#        u1 = getattr(thissim,field)
#        if(not(field=='ux' or field=='uy')):
#            u1=u1[0,:,:]
#
#        if(direction=='x' or direction=='r'):
#            n1_factor = int(dx_max/thissim.dx)
#            n2_factor = int(thissim.dx/dh)
#            u1 = u1[:,0::n1_factor]
#            u2 = attribute[0,0::n2_factor,0::n2_factor]
#            u2 = u2[:,0::n1_factor]
#        elif(direction=='y' or direction=='th'):
#            n1_factor = int(dx_max/thissim.dy)
#            n2_factor = int(thissim.dy/dh)
#            u1 = u1[0::n1_factor,:]
#            u2 = attribute[0,0::n2_factor,0::n2_factor]
#            u2 = u2[0::n1_factor,:]
#
#        if(direction=='x' or direction=='r'):
#           twonorms[i] = (twonorm(u1[:,strip],u2[:,strip],thissim.dy*sims[0].r[strip]))
#           maxerrs[i] = (maxerror(u1[:,strip],u2[:,strip]))
#        elif(direction=='y' or direction=='th'):
#           twonorms[i] = (twonorm(u1[strip,:],u2[strip,:],thissim.dx))
#           maxerrs[i] = (maxerror(u1[strip,:],u2[strip,:]))
    if(not quiet):
        print('Two-norm computed for field:',field,', along strip:',strip)
        if(direction=='x'):
            print('Along x-direction')
        elif(direction=='r'):
            print('Along r-direction')
        elif(direction=='y'):
            print('Along y-direction')
        elif(direction=='th'):
            print('Along th-direction')

    if not noerr:
        return twonorms, maxerrs
    else:
        return twonorms
示例#7
0
def twonorm_accuracy1D(simulations,
                       field='ur',
                       strip=1,
                       direction='r',
                       varfile='ogvar.dat',
                       noerr=True,
                       quiet=True):
    """
    Assessment of accuracy of simulation:
    Computes the two-norm error of all available simulation, where the simulation
    with the maximum amount of grid points is used as the correct/reference solution.
    E.g., for runs with grid points assessment of accuracy of x-component of velocity
    along the y-direction, for runs with grid points nxgrid = n, 2n, 4n, 8n, compute

    || u_n - u_0 || = dy \sum\limits_{n=0}^n (sqrt(u_n(x_n)-u_0(x_8n)))
    
    for all runs (except for the 8n case, used as reference).

    Requires that the runs have matching grids, that is, grid refined by a factor of 2m,
    and grids adjusted so that the grid point overlap (needs ofset if periodic BC is used).

    call signature:
      twonorm_accuracy(simulations)

    Keyword arguments:

    *simulations*
      array of simulation names to be included in the computations

    *field*
      variable used in accuracy assessment

    *varfile*:
      name of varfile to read from each sim

    *noerr*:
      set to false if you want to return an array of maximum error along strip, in 
      addition to the two-norm

    Returns
      array of two-norms where the larges array is used as base 
    """

    import numpy as np
    import os as os
    from pencilnew import read
    from pencilnew import sim

    # Find directories to include in accuracy assessment
    sims = []
    for simulation in simulations:
        sims.append(sim.get(simulation, quiet=True))

    # Sort runs by size of grid spacing
    sims = sim.sort(sims, 'dx', reverse=True)

    # From this point we only need the varfile to compute accuracy
    # Need to update dim to ogdim for reading of ogvar to be done
    # correctly from simulation object
    for i, thissim in enumerate(sims):
        sims[i].dim = read.ogdim(datadir=thissim.datadir)
        sims[i] = read.ogvar(sim=thissim, trimall=True, varfile=varfile)

    # Check that increase in size is correct for use in two-norm calculation
    nsims = len(sims)
    nx_min = sims[0].r.size
    ny_min = sims[0].th.size
    for thissim in sims:
        if ((thissim.r.size - 1) % (nx_min - 1) != 0):
            print('ERROR: Incorrect size in r-dir')
            print('sims.r', thissim.r.size)
            print('nx_min', nx_min)
            return False

        if (thissim.th.size % ny_min != 0):
            print('ERROR: Incorrect size in th-dir')
            return False

    # Check that all var-files are for the same time
    t = sims[0].t
    for thissim in sims:
        if thissim.t != t:
            print('WARNING: Incorrect time for one or more simulations')

    # Now we are sure that first coordinate of r and th are the same for all runs
    # Can compute the two-norms for increasing sizes. Use largest size as normalization of error
    twonorms = np.zeros(nsims - 1)
    maxerrs = np.zeros(nsims - 1)

    # Compute array of factor used to jump indices when comparing two arrays of size N and 2N etc.
    # Usually n2_fac = [8, 4, 2] or similar
    n2_fac = np.empty(nsims - 1)
    for i, thissim in enumerate(sims[:-1]):
        n2_fac[i] = thissim.dx / sims[-1].dx

    u2 = getattr(sims[-1], field)
    if not (field == 'ux' or field == 'uy'):
        u2 = u2[0, :, :]

    for i, thissim in enumerate(sims[:-1]):
        u1 = getattr(thissim, field)
        if not (field == 'ux' or field == 'uy'):
            u1 = u1[0, :, :]

        dr = np.empty(thissim.r.size)
        dr[0:-1] = thissim.r[1:] - thissim.r[0:-1]
        dr[-1] = dr[-2]
        dth = thissim.dy
        twonorms[i] = 0.
        n2 = n2_fac[i]
        if (direction == 'r'):
            r = sims[0].r[strip]
            j = int(strip * sims[0].dx / thissim.dx)
            for k in range(thissim.th.size):
                twonorms[i] = twonorms[i] + dth * r * (
                    u1[k, j] - u2[int(k * n2), int(j * n2)])**2
        elif (direction == 'th'):
            k = int(strip * sims[0].dx / thissim.dx)
            for j in range(thissim.r.size):
                twonorms[i] = twonorms[i] + dr[j] * (
                    u1[k, j] - u2[int(k * n2), int(j * n2)])**2
        else:
            print('ERROR: Invalid direction chosen')
            return False

        twonorms[i] = np.sqrt(twonorms[i])

    if not noerr:
        return twonorms, maxerrs
    else:
        return twonorms