Beispiel #1
0
    def Ricci__generate_Ccode(Ricci_exprs_list):
        Ricci_SymbExpressions     = Ricci_exprs_list[0]

        print("Generating C code for Ricci tensor (FD_order="+str(FD_order)+") in "+par.parval_from_str("reference_metric::CoordSystem")+" coordinates.")
        start = time.time()

        # Store original finite-differencing order:
        FD_order_orig = par.parval_from_str("finite_difference::FD_CENTDERIVS_ORDER")
        # Set new finite-differencing order:
        par.set_parval_from_str("finite_difference::FD_CENTDERIVS_ORDER", FD_order)

        Ricci_string = fin.FD_outputC("returnstring", Ricci_SymbExpressions,
                                       params="outCverbose=False,SIMD_enable=True,GoldenKernelsEnable=True")

        filename = "BSSN_Ricci_FD_order_"+str(FD_order)+".h"
        with open(os.path.join(outdir, filename), "w") as file:
            file.write(lp.loop(["i2","i1","i0"],["cctk_nghostzones[2]","cctk_nghostzones[1]","cctk_nghostzones[0]"],
           ["cctk_lsh[2]-cctk_nghostzones[2]","cctk_lsh[1]-cctk_nghostzones[1]","cctk_lsh[0]-cctk_nghostzones[0]"],
                               ["1","1","SIMD_width"],
                                ["#pragma omp parallel for",
                                 "#include \"rfm_files/rfm_struct__SIMD_outer_read2.h\"",
                                 r"""    #include "rfm_files/rfm_struct__SIMD_outer_read1.h"
    #if (defined __INTEL_COMPILER && __INTEL_COMPILER_BUILD_DATE >= 20180804)
        #pragma ivdep         // Forces Intel compiler (if Intel compiler used) to ignore certain SIMD vector dependencies
        #pragma vector always // Forces Intel compiler (if Intel compiler used) to vectorize
    #endif"""],"",
                    "#include \"rfm_files/rfm_struct__SIMD_inner_read0.h\"\n"+Ricci_string))

        # Restore original finite-differencing order:
        par.set_parval_from_str("finite_difference::FD_CENTDERIVS_ORDER", FD_order_orig)

        end = time.time()
        print("(BENCH) Finished Ricci C codegen (FD_order="+str(FD_order)+") in " + str(end - start) + " seconds.")
def cf_from_gammaDD(gammaDD):
    global cf

    if gammaDD == None:
        gammaDD = ixp.declarerank2("gammaDD", "sym01")

    # \bar{Lambda}^i = \bar{gamma}^{jk}(\bar{Gamma}^i_{jk} - \hat{Gamma}^i_{jk}).
    gammabarDD_hDD(gammaDD)
    gammabarUU, gammabarDET = ixp.symm_matrix_inverter3x3(gammabarDD)
    gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD)

    cf = sp.sympify(0)

    if par.parval_from_str("EvolvedConformalFactor_cf") == "phi":
        # phi = \frac{1}{12} log(\frac{gamma}{\bar{gamma}}).
        cf = sp.Rational(1, 12) * sp.log(gammaDET / gammabarDET)
    elif par.parval_from_str("EvolvedConformalFactor_cf") == "chi":
        # chi = exp(-4*phi) = exp(-4*\frac{1}{12}*(\frac{gamma}{\bar{gamma}}))
        #      = exp(-\frac{1}{3}*log(\frac{gamma}{\bar{gamma}})) = (\frac{gamma}{\bar{gamma}})^{-1/3}.
        #
        cf = (gammaDET / gammabarDET)**(-sp.Rational(1, 3))
    elif par.parval_from_str("EvolvedConformalFactor_cf") == "W":
        # W = exp(-2*phi) = exp(-2*\frac{1}{12}*log(\frac{gamma}{\bar{gamma}}))
        #   = exp(-\frac{1}{6}*log(\frac{gamma}{\bar{gamma}})) = (\frac{gamma}{bar{gamma}})^{-1/6}.
        cf = (gammaDET / gammabarDET)**(-sp.Rational(1, 6))
    else:
        print("Error EvolvedConformalFactor_cf type = \"" +
              par.parval_from_str("EvolvedConformalFactor_cf") + "\" unknown.")
        sys.exit(1)
def EigenCoord_Cart_to_xx():
    # Step 1: Find the Eigen-Coordinate and set up the Eigen-Coordinate's reference metric:
    CoordSystem_orig = par.parval_from_str("reference_metric::CoordSystem")
    par.set_parval_from_str("reference_metric::CoordSystem",rfm.get_EigenCoord())
    rfm.reference_metric()

    # Step 2: Output the Eigen-Coordinate mapping from Cartesian->xx:
    # Step 2.a: Sanity check: First make sure that rfm.Cart_to_xx has been set. Error out if not!
    if rfm.Cart_to_xx[0] == 0 or rfm.Cart_to_xx[1] == 0 or rfm.Cart_to_xx[2] == 0:
        print("ERROR: rfm.Cart_to_xx[], which maps Cartesian -> xx, has not been set for")
        print("       reference_metric::CoordSystem = "+par.parval_from_str("reference_metric::CoordSystem"))
        print("       Boundary conditions in curvilinear coordinates REQUiRE this be set.")
        sys.exit(1)
    # Step 2.b: Output C code for the Eigen-Coordinate mapping from Cartesian->xx:
    outstr = """    // Cart_to_xx for EigenCoordinate """+rfm.get_EigenCoord()+r""" (orig coord = """+CoordSystem_orig+");\n"
    outstr += outputC([rfm.Cart_to_xx[0],rfm.Cart_to_xx[1],rfm.Cart_to_xx[2]],
                      ["Cart_to_xx0_inbounds","Cart_to_xx1_inbounds","Cart_to_xx2_inbounds"],
                      filename="returnstring", params="preindent=2")

    # Step 3: Restore reference_metric::CoordSystem back to the original CoordSystem
    par.set_parval_from_str("reference_metric::CoordSystem",CoordSystem_orig)
    rfm.reference_metric()

    # Step 4: Return EigenCoord Cart_to_xx C code
    return outstr
Beispiel #4
0
def MaxwellCartesian_ID():
    DIM = par.parval_from_str("grid::DIM")

    x, y, z = gri.register_gridfunctions("AUX", ["x", "y", "z"])
    gammaDD = ixp.register_gridfunctions_for_single_rank2("AUX","gammaDD", "sym01") # The AUX or EVOL designation is *not*
                                                                                    # used in diagnostic modules.

    # Step 1: Declare free parameters intrinsic to these initial data
    amp,lam = par.Cparameters("REAL",__name__,["amp","lam"], [1.0,1.0]) # __name__ = "MaxwellCartesian_ID", this module's name

    # Step 2: Set the initial data
    system = par.parval_from_str("System_to_use")
    if system == "System_I" or system == "System_II":
        global AidD,EidD,psi_ID
        AidD = ixp.zerorank1()

        EidD = ixp.zerorank1()
        EidU = ixp.zerorank1()
        # Set the coordinate transformations:
        radial = sp.sqrt(x*x + y*y + z*z)
        polar = sp.atan2(sp.sqrt(x*x + y*y),z)
        EU_phi = 8*amp*radial*sp.sin(polar)*lam*lam*sp.exp(-lam*radial*radial)
        EidU[0] = -(y * EU_phi)/sp.sqrt(x*x + y*y)
        EidU[1] = (x * EU_phi)/sp.sqrt(x*x + y*y)
        # The z component (2)is zero.
        for i in range(DIM):
            for j in range(DIM):
                EidD[i] += gammaDD[i][j] * EidU[j]

        psi_ID = sp.sympify(0)
        if system == "System_II":
            global Gamma_ID
            Gamma_ID = sp.sympify(0)
    else:
        print("Invalid choice of system: System_to_use must be either System_I or System_II")
Beispiel #5
0
def gfaccess(gfarrayname="", varname="", ijklstring=""):
    found_registered_gf = False
    for gf in glb_gridfcs_list:
        if gf.name == varname:
            if found_registered_gf:
                print("Error: found duplicate gridfunction name: " + gf.name)
                sys.exit(1)
            found_registered_gf = True

    if not found_registered_gf:
        print("Error: gridfunction \"" + varname + "\" is not registered!")
        sys.exit(1)

    gftype = find_gftype(varname)

    DIM = par.parval_from_str("DIM")
    retstring = ""
    if par.parval_from_str("GridFuncMemAccess") == "SENRlike":
        if gfarrayname == "":
            print(
                "Error: GridFuncMemAccess = SENRlike requires gfarrayname be passed to gfaccess()"
            )
            sys.exit(1)
        # FIXME: if gftype == "AUX" then override gfarrayname to aux_gfs[].
        #        This enables expressions containing a mixture of AUX and EVOL
        #        gridfunctions, though in a slightly hacky way.
        if gftype == "AUX":
            gfarrayname = "aux_gfs"
        elif gftype == "AUXEVOL":
            gfarrayname = "auxevol_gfs"
        # Return gfarrayname[IDX3(varname,i0)] for DIM=1, gfarrayname[IDX3(varname,i0,i1)] for DIM=2, etc.
        retstring += gfarrayname + "[IDX" + str(
            DIM + 1) + "S(" + varname.upper() + "GF" + ", "
    elif par.parval_from_str("GridFuncMemAccess") == "ETK":
        # Return varname[CCTK_GFINDEX3D(i0,i1,i2)] for DIM=3. Error otherwise
        if DIM != 3:
            print(
                "Error: GridFuncMemAccess = ETK currently requires that gridfunctions be 3D. Can be easily extended."
            )
            sys.exit(1)
        if gfarrayname == "rhs_gfs":
            retstring += varname + "_rhsGF" + "[CCTK_GFINDEX" + str(
                DIM) + "D(cctkGH, "
        else:
            retstring += varname + "GF" + "[CCTK_GFINDEX" + str(
                DIM) + "D(cctkGH, "
    else:
        print("grid::GridFuncMemAccess = " +
              par.parval_from_str("GridFuncMemAccess") + " not supported")
        sys.exit(1)
    if ijklstring == "":
        for i in range(DIM):
            retstring += "i" + str(i)
            if i != DIM - 1:
                retstring += ', '
    else:
        retstring += ijklstring
    return retstring + ")]"
 def unique_idx(idx4):
     # os and sz are set *just for the purposes of ensuring indices are ordered in memory*
     #    Do not modify the values of os and sz.
     os = 50  # offset
     sz = 100 # assumed size in each direction
     if par.parval_from_str("MemAllocStyle") == "210":
         return str(int(idx4[0])+os + sz*( (int(idx4[1])+os) + sz*( (int(idx4[2])+os) + sz*( int(idx4[3])+os ) ) ))
     if par.parval_from_str("MemAllocStyle") == "012":
         return str(int(idx4[3])+os + sz*( (int(idx4[2])+os) + sz*( (int(idx4[1])+os) + sz*( int(idx4[0])+os ) ) ))
     print("Error: MemAllocStyle = "+par.parval_from_str("MemAllocStyle")+" unsupported.")
     sys.exit(1)
Beispiel #7
0
def detgammabar_and_derivs():
    # Step 5.a: Declare as globals all expressions that may be used
    #           outside this function, declare BSSN gridfunctions
    #           if not defined already, and set DIM=3.
    global detgammabar,detgammabar_dD,detgammabar_dDD
    hDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already()
    DIM = 3

    detgbarOverdetghat = sp.sympify(1)
    detgbarOverdetghat_dD = ixp.zerorank1()
    detgbarOverdetghat_dDD = ixp.zerorank2()

    if par.parval_from_str(thismodule + "::detgbarOverdetghat_equals_one") == "False":
        print("Error: detgbarOverdetghat_equals_one=\"False\" is not fully implemented yet.")
        exit(1)
    ## Approach for implementing detgbarOverdetghat_equals_one=False:
    #     detgbarOverdetghat = gri.register_gridfunctions("AUX", ["detgbarOverdetghat"])
    #     detgbarOverdetghatInitial = gri.register_gridfunctions("AUX", ["detgbarOverdetghatInitial"])
    #     detgbarOverdetghat_dD = ixp.declarerank1("detgbarOverdetghat_dD")
    #     detgbarOverdetghat_dDD = ixp.declarerank2("detgbarOverdetghat_dDD", "sym01")

    # Step 8d: Define detgammabar, detgammabar_dD, and detgammabar_dDD (needed for \partial_t \bar{\Lambda}^i below)
    detgammabar = detgbarOverdetghat * rfm.detgammahat

    detgammabar_dD = ixp.zerorank1()
    for i in range(DIM):
        detgammabar_dD[i] = detgbarOverdetghat_dD[i] * rfm.detgammahat + detgbarOverdetghat * rfm.detgammahatdD[i]

    detgammabar_dDD = ixp.zerorank2()
    for i in range(DIM):
        for j in range(DIM):
            detgammabar_dDD[i][j] = detgbarOverdetghat_dDD[i][j] * rfm.detgammahat + \
                                    detgbarOverdetghat_dD[i] * rfm.detgammahatdD[j] + \
                                    detgbarOverdetghat_dD[j] * rfm.detgammahatdD[i] + \
                                    detgbarOverdetghat * rfm.detgammahatdDD[i][j]
Beispiel #8
0
def register_gridfunctions_for_single_rank2(gf_type,
                                            gf_basename,
                                            symmetry_option,
                                            DIM=-1):
    # Step 0: Verify the gridfunction basename is valid:
    gri.verify_gridfunction_basename_is_valid(gf_basename)

    # Step 1: Declare a list of lists of SymPy variables,
    #         where IDX_OBJ_TMP[i][j] = gf_basename+str(i)+str(j)
    IDX_OBJ_TMP = declarerank2(gf_basename, symmetry_option, DIM)

    # Step 2: register each gridfunction, being careful not
    #         not to store duplicates due to rank-2 symmetries.
    if DIM == -1:
        DIM = par.parval_from_str("DIM")
    # Register only unique gridfunctions. Otherwise
    # rank-2 symmetries might result in duplicates
    gf_list = []
    for i in range(DIM):
        for j in range(DIM):
            save = True
            for l in range(len(gf_list)):
                if gf_list[l] == str(IDX_OBJ_TMP[i][j]):
                    save = False
            if save == True:
                gf_list.append(str(IDX_OBJ_TMP[i][j]))
    gri.register_gridfunctions(gf_type,
                               gf_list,
                               rank=2,
                               is_indexed=True,
                               DIM=DIM)

    # Step 3: Return array of SymPy variables
    return IDX_OBJ_TMP
Beispiel #9
0
 def out__type_var(in_var, AddPrefix_for_UpDownWindVars=True):
     varname = str(in_var)
     # Disable prefixing upwinded and downwinded variables
     # if the upwind control vector algorithm is disabled.
     if upwindcontrolvec == "":
         AddPrefix_for_UpDownWindVars = False
     if AddPrefix_for_UpDownWindVars:
         if "_dupD" in varname:  # Variables suffixed with "_dupD" are set
             #                    to be the "pure" upwinded derivative,
             #                    before the upwinding algorithm has been
             #                    applied. However, when they are used
             #                    in the RHS expressions, it is assumed
             #                    that the up. algorithm has been applied.
             #                    To ensure consistency we rename all
             #                    _dupD suffixed variables as
             #                    _dupDPUREUPWIND, and use them as input
             #                    into the upwinding algorithm. The output
             #                    will be the original _dupD variable.
             varname = "UpwindAlgInput" + varname
         if "_ddnD" in varname:  # For consistency with _dupD
             varname = "UpwindAlgInput" + varname
     if outCparams.SIMD_enable == "True":
         return "const REAL_SIMD_ARRAY " + varname
     else:
         TYPE = par.parval_from_str("PRECISION")
         return "const " + TYPE + " " + varname
Beispiel #10
0
    def __init__(self, fd_order=2, vars_at_inf_default = 0., vars_radial_falloff_power_default = 3., vars_speed_default = 1.):
        evolved_variables_list, _, _ = gri.gridfunction_lists()

        # set class finite differencing order
        self.fd_order = fd_order

        NRPy_FD_order = par.parval_from_str("finite_difference::FD_CENTDERIVS_ORDER")

        if NRPy_FD_order < fd_order:
            print("ERROR: The global central finite differencing order within NRPy+ must be greater than or equal to the Sommerfeld boundary condition's finite differencing order")
            sys.exit(1)

        # Define class dictionaries to store sommerfeld parameters for each EVOL gridfunction

        # EVOL gridfunction asymptotic value at infinity
        self.vars_at_infinity = {}

        # EVOL gridfunction wave speed at outer boundaries
        self.vars_speed = {}

        # EVOL gridfunction radial falloff power
        self.vars_radial_falloff_power = {}

        # Set default values for each specific EVOL gridfunction
        for gf in evolved_variables_list:
            self.vars_at_infinity[gf.upper() + 'GF'] = vars_at_inf_default
            self.vars_radial_falloff_power[gf.upper() + 'GF'] = vars_radial_falloff_power_default
            self.vars_speed[gf.upper() + 'GF'] = vars_speed_default
Beispiel #11
0
def ccode_postproc(string):
    PRECISION = par.parval_from_str("PRECISION")

    # In the C math library, e.g., pow(x,y) assumes x and y are doubles, and returns a double.
    #  If x and y are floats, then for consistency should use powf(x,y) instead.
    #  Similarly, in the case of x and y being long doubles, should use powl(x,y) for consistency.
    # First we find the appropriate suffix depending on the desired precision:
    cmathsuffix = ""
    if PRECISION == "double":
        pass
    elif PRECISION == "long double":
        cmathsuffix = "l"
    elif PRECISION == "float":
        cmathsuffix = "f"
    else:
        print("Error: "+__name__+"::PRECISION = \""+ PRECISION +"\" not supported")
        sys.exit(1)
    # ... then we append the above suffix to standard C math library functions:
    for func in ['pow', 'sqrt', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'exp', 'log', 'fabs']:
        string2 = re.sub(func+r'\(', func + cmathsuffix+"(", string); string = string2

    # Finally, SymPy prefers to output Rationals as long-double fractions.
    #  E.g., Rational(1,3) is output as 1.0L/3.0L.
    #  The Intel compiler vectorizer complains miserably about this,
    #  and strictly speaking it is useless when we're in double precision.
    # So here we get rid of the "L" suffix on floating point numbers:
    if PRECISION!="long double":
        string2 = re.sub(r'([0-9.]+)L/([0-9.]+)L', '(\\1 / \\2)', string); string = string2

    return string
def ScalarWave_RHSs():
    # Step 1: Get the spatial dimension, defined in the
    #         NRPy+ "grid" module.
    DIM = par.parval_from_str("DIM")

    # Step 2: Register gridfunctions that are needed as input
    #         to the scalar wave RHS expressions.
    uu, vv = gri.register_gridfunctions("EVOL", ["uu", "vv"])

    # Step 3: Declare the rank-2 indexed expression \partial_{ij} u,
    #         which is symmetric about interchange of indices i and j
    #         Derivative variables like these must have an underscore
    #         in them, so the finite difference module can parse the
    #         variable name properly.
    uu_dDD = ixp.declarerank2("uu_dDD", "sym01")

    # Step 4: Specify RHSs as global variables,
    #         to enable access outside this
    #         function (e.g., for C code output)
    global uu_rhs, vv_rhs

    # Step 5: Define right-hand sides for the evolution.
    uu_rhs = vv
    vv_rhs = 0
    for i in range(DIM):
        vv_rhs += wavespeed * wavespeed * uu_dDD[i][i]
Beispiel #13
0
def declarerank4(objname, symmetry_option, DIM=-1):
    if DIM == -1:
        DIM = par.parval_from_str("DIM")
    IDX_OBJ_TMP = [[[[
        sp.sympify(objname + str(i) + str(j) + str(k) + str(l))
        for l in range(DIM)
    ] for k in range(DIM)] for j in range(DIM)] for i in range(DIM)]
    for i in range(DIM):
        for j in range(DIM):
            for k in range(DIM):
                for l in range(DIM):
                    IDX_OBJ_TMP[i][j][k][l] = sp.sympify(objname + str(i) +
                                                         str(j) + str(k) +
                                                         str(l))
                    if symmetry_option in ('sym01', 'sym01_sym23'):
                        if (j < i):
                            IDX_OBJ_TMP[i][j][k][l] = IDX_OBJ_TMP[j][i][k][l]
                    if symmetry_option == "sym12":
                        if (k < j):
                            IDX_OBJ_TMP[i][j][k][l] = IDX_OBJ_TMP[i][k][j][l]
                    if symmetry_option in ('sym23', 'sym01_sym23'):
                        if (l < k):
                            IDX_OBJ_TMP[i][j][k][l] = IDX_OBJ_TMP[i][j][l][k]
                    if symmetry_option not in ('sym01', 'sym23', 'sym01_sym23',
                                               'nosym'):
                        print("Error: symmetry option " + symmetry_option +
                              " unsupported.")
                        sys.exit(1)
    return apply_symmetry_condition_to_derivatives(IDX_OBJ_TMP)
Beispiel #14
0
def outputC_register_C_functions_and_NRPy_basic_defines():
    # First register C functions needed by outputC

    # Then set up the dictionary entry for outputC in NRPy_basic_defines
    Nbd_str  = r"""
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "string.h" // "string.h Needed for strncmp, etc.
#include "stdint.h" // "stdint.h" Needed for Windows GCC 6.x compatibility, and for int8_t

#ifndef M_PI
#define M_PI 3.141592653589793238462643383279502884L
#endif
#ifndef M_SQRT1_2
#define M_SQRT1_2 0.707106781186547524400844362104849039L
#endif

#ifndef MIN
#define MIN(A, B) ( ((A) < (B)) ? (A) : (B) )
#endif
#ifndef MAX
#define MAX(A, B) ( ((A) > (B)) ? (A) : (B) )
#endif

#ifdef __cplusplus
#define restrict __restrict__
#endif
"""
    Nbd_str += "#define REAL " + par.parval_from_str("outputC::PRECISION") + "\n"
    outC_NRPy_basic_defines_h_dict["outputC"] = Nbd_str
Beispiel #15
0
def SphericalGaussian(CoordSystem="Cartesian",
                      default_time=0,
                      default_sigma=3):
    # Step 1: Set parameters for the wave
    DIM = par.parval_from_str("grid::DIM")

    # Step 2: Set up Cartesian coordinates in terms of the native CoordSystem we have chosen.
    #         E.g., if CoordSystem="Cartesian", then xxCart = [xx[0],xx[1],xx[2]]
    #         or if CoordSystem="Spherical", then xxCart = [xx[0]*sp.sin(xx[1])*sp.cos(xx[2]),
    #                                                       xx[0]*sp.sin(xx[1])*sp.sin(xx[2]),
    #                                                       xx[0]*sp.cos(xx[1])]
    par.set_parval_from_str("reference_metric::CoordSystem", CoordSystem)
    rfm.reference_metric()  # Must call this function to specify rfm.xxCart
    xxCart = rfm.xxCart

    # Step 3: Declare free parameters intrinsic to these initial data
    time = par.Cparameters("REAL", thismodule, "time", default_time)
    sigma = par.Cparameters("REAL", thismodule, "sigma", default_sigma)

    # Step 4: Compute r
    r = sp.sympify(0)
    for i in range(DIM):
        r += xxCart[i]**2
    r = sp.sqrt(r)

    # Step 5: Set initial data for uu and vv, where vv_ID = \partial_t uu_ID.
    global uu_ID, vv_ID
    # uu_ID = (r - wavespeed*time)/r * sp.exp(- (r - wavespeed*time)**2 / (2*sigma**2) )
    uu_ID = (+(r - wavespeed * time) / r * sp.exp(-(r - wavespeed * time)**2 /
                                                  (2 * sigma**2)) +
             (r + wavespeed * time) / r * sp.exp(-(r + wavespeed * time)**2 /
                                                 (2 * sigma**2)))
    vv_ID = sp.diff(uu_ID, time)
Beispiel #16
0
def PlaneWave(CoordSystem="Cartesian",
              default_time=0,
              default_k0=1,
              default_k1=1,
              default_k2=1):
    # Step 1: Set parameters defined in other modules
    DIM = par.parval_from_str("grid::DIM")

    # Step 2: Set up Cartesian coordinates in terms of the native CoordSystem we have chosen.
    #         E.g., if CoordSystem="Cartesian", then xxCart = [xx[0],xx[1],xx[2]]
    #         or if CoordSystem="Spherical", then xxCart = [xx[0]*sp.sin(xx[1])*sp.cos(xx[2]),
    #                                                       xx[0]*sp.sin(xx[1])*sp.sin(xx[2]),
    #                                                       xx[0]*sp.cos(xx[1])]
    par.set_parval_from_str("reference_metric::CoordSystem", CoordSystem)
    rfm.reference_metric()
    xxCart = rfm.xxCart

    # Step 3: Declare free parameters intrinsic to these initial data
    time = par.Cparameters("REAL", thismodule, "time", default_time)
    kk = par.Cparameters("REAL", thismodule, ["kk0", "kk1", "kk2"],
                         [default_k0, default_k1, default_k2])

    # Step 4: Normalize the k vector
    kk_norm_factor = sp.sqrt(kk[0]**2 + kk[1]**2 + kk[2]**2)

    # Step 5: Compute k_norm.x
    dot_product = sp.sympify(0)
    for i in range(DIM):
        dot_product += kk[i] * xxCart[i]
    dot_product /= kk_norm_factor

    # Step 6: Set initial data for uu and vv, where vv_ID = \partial_t uu_ID.
    global uu_ID, vv_ID
    uu_ID = sp.sin(dot_product - wavespeed * time) + 2
    vv_ID = sp.diff(uu_ID, time)
Beispiel #17
0
 def ijkl_string(idx4):
     DIM = par.parval_from_str("DIM")
     retstring = ""
     for i in range(DIM):
         if i > 0:
             # Add a comma
             retstring += ","
         retstring += "i" + str(i) + "+" + str(idx4[i])
     return retstring.replace("+-", "-").replace("+0", "")
def ScalarWaveCurvilinear_RHSs():
    # Step 1: Get the spatial dimension, defined in the
    #         NRPy+ "grid" module. With reference metrics,
    #         this must be set to 3 or fewer.
    DIM = par.parval_from_str("DIM")

    # Step 2: Set up the reference metric and
    #         quantities derived from the
    #         reference metric.
    rfm.reference_metric()

    # Step 3: Compute the contracted Christoffel symbols:
    contractedGammahatU = ixp.zerorank1()
    for k in range(DIM):
        for i in range(DIM):
            for j in range(DIM):
                contractedGammahatU[k] += rfm.ghatUU[i][j] * rfm.GammahatUDD[k][i][j]

    # Step 4: Register gridfunctions that are needed as input
    #         to the scalar wave RHS expressions.
    uu, vv = gri.register_gridfunctions("EVOL",["uu","vv"])

    # Step 5a: Declare the rank-1 indexed expression \partial_{i} u,
    #          Derivative variables like these must have an underscore
    #          in them, so the finite difference module can parse the
    #          variable name properly.
    uu_dD = ixp.declarerank1("uu_dD")

    # Step 5b: Declare the rank-2 indexed expression \partial_{ij} u,
    #          which is symmetric about interchange of indices i and j
    #          Derivative variables like these must have an underscore
    #          in them, so the finite difference module can parse the
    #          variable name properly.
    uu_dDD = ixp.declarerank2("uu_dDD","sym01")

    # Step 7: Specify RHSs as global variables,
    #         to enable access outside this
    #         function (e.g., for C code output)
    global uu_rhs,vv_rhs

    # Step 6: Define right-hand sides for the evolution.
    # Step 6a: uu_rhs = vv:
    uu_rhs = vv
    # Step 6b: The right-hand side of the \partial_t v equation
    #          is given by:
    #          \hat{g}^{ij} \partial_i \partial_j u - \hat{\Gamma}^i \partial_i u.
    #          ^^^^^^^^^^^^ PART 1 ^^^^^^^^^^^^^^^^ ^^^^^^^^^^ PART 2 ^^^^^^^^^^^
    vv_rhs = 0
    for i in range(DIM):
        # PART 2:
        vv_rhs -= contractedGammahatU[i]*uu_dD[i]
        for j in range(DIM):
            # PART 1:
            vv_rhs += rfm.ghatUU[i][j]*uu_dDD[i][j]

    vv_rhs *= wavespeed*wavespeed
def f_of_r(r, M):
    if par.parval_from_str("drop_fr"):
        return sp.sympify(0)
    x = sp.sympify(2) * M / r
    L = sp.sympify(0) + \
        noif.coord_greater_bound(x,sp.sympify(0))*noif.coord_less_bound(x,sp.sympify(1))*nrpyDilog(x)\
       +sp.Rational(1,2)*sp.log(noif.coord_greater_bound(x,sp.sympify(0))*x + noif.coord_leq_bound(x,sp.sympify(1)))\
       *sp.log(noif.coord_less_bound(x,sp.sympify(1))*(sp.sympify(1)-x) + noif.coord_geq_bound(x,sp.sympify(1)))
    f = r*r*(sp.sympify(2)*r-sp.sympify(3)*M)*sp.Rational(1,8)/(M**3)*L\
      +(M*M+sp.sympify(3)*M*r-sp.sympify(6)*r*r)*sp.Rational(1,12)/(M*M)*sp.log(r*sp.Rational(1,2)/M)\
      +sp.Rational(11,72) + M*sp.Rational(1,3)/r + r*sp.Rational(1,2)/M - r*r*sp.Rational(1,2)/(M*M)
    return f
Beispiel #20
0
def define_LeviCivitaSymbol(DIM=-1):
    if DIM == -1:
        DIM = par.parval_from_str("DIM")

    LeviCivitaSymbol = ixp.zerorank3()

    for i in range(DIM):
        for j in range(DIM):
            for k in range(DIM):
                # From https://codegolf.stackexchange.com/questions/160359/levi-civita-symbol :
                LeviCivitaSymbol[i][j][k] = (i - j) * (j - k) * (k - i) / 2
    return LeviCivitaSymbol
def fp_of_r(r, M):
    if par.parval_from_str("drop_fr"):
        return sp.sympify(0)
    x = sp.sympify(2) * M / r
    L = sp.sympify(0) + \
        noif.coord_greater_bound(x,sp.sympify(0))*noif.coord_less_bound(x,sp.sympify(1))*nrpyDilog(x)\
       +sp.Rational(1,2)*sp.log(noif.coord_greater_bound(x,sp.sympify(0))*x + noif.coord_leq_bound(x,sp.sympify(1)))\
       *sp.log(noif.coord_less_bound(x,sp.sympify(1))*(sp.sympify(1)-x) + noif.coord_geq_bound(x,sp.sympify(1)))
    Lp  = sp.sympify(0) + noif.coord_greater_bound(x,sp.sympify(0))*noif.coord_less_bound(x,sp.sympify(1)) * -sp.Rational(1,2) *\
         (sp.log(noif.coord_less_bound(x,sp.sympify(1))*(sp.sympify(1)-x) + noif.coord_geq_bound(x,sp.sympify(1)))/(x+sp.sympify(1e-100))\
         +sp.log(noif.coord_greater_bound(x,sp.sympify(0))*x + noif.coord_leq_bound(x,sp.sympify(1)))/(sp.sympify(1)-x+sp.sympify(1e-100)))
    fp  = sp.sympify(3)*r*(r-M)*sp.Rational(1,4)/(M**3)*L + (sp.sympify(2)*r-sp.sympify(3)*M)*sp.Rational(1,4)/(M*M)*Lp\
          +(sp.sympify(3)*M-12*r)*sp.Rational(1,12)/(M*M)*sp.log(r*sp.Rational(1,2)/M) + (M*M+sp.sympify(3)*M*r-sp.sympify(6)*r*r)*sp.Rational(1,12)/(r*M*M)\
          -M*sp.Rational(1,3)/(r*r) + sp.Rational(1,2)/M - r/(M*M)
    return fp
Beispiel #22
0
    def enforce_detgammabar_eq_detgammahat__generate_symbolic_expressions_and_C_code():
        ######################################
        # START: GENERATE SYMBOLIC EXPRESSIONS
        # Store original finite-differencing order:
        FD_order_orig = par.parval_from_str("finite_difference::FD_CENTDERIVS_ORDER")
        # Set new finite-differencing order:
        par.set_parval_from_str("finite_difference::FD_CENTDERIVS_ORDER", FD_order)

        # Enable rfm_precompute infrastructure, which results in 
        #   BSSN RHSs that are free of transcendental functions,
        #   even in curvilinear coordinates, so long as 
        #   ConformalFactor is set to "W" (default).
        cmd.mkdir(os.path.join(outdir,"rfm_files/"))
        par.set_parval_from_str("reference_metric::enable_rfm_precompute","True")
        par.set_parval_from_str("reference_metric::rfm_precompute_Ccode_outdir",os.path.join(outdir,"rfm_files/"))

        import BSSN.Enforce_Detgammabar_Constraint as EGC
        enforce_detg_constraint_symb_expressions = EGC.Enforce_Detgammabar_Constraint_symb_expressions()

        # Now that we are finished with all the rfm hatted
        #           quantities in generic precomputed functional
        #           form, let's restore them to their closed-
        #           form expressions.
        par.set_parval_from_str("reference_metric::enable_rfm_precompute","False") # Reset to False to disable rfm_precompute.
        rfm.ref_metric__hatted_quantities()

        # Restore original finite-differencing order:
        par.set_parval_from_str("finite_difference::FD_CENTDERIVS_ORDER", FD_order)
        # END: GENERATE SYMBOLIC EXPRESSIONS
        ######################################


        start = time.time()
        print("Generating optimized C code (FD_order="+str(FD_order)+") for gamma constraint. May take a while, depending on CoordSystem.")
        enforce_gammadet_string = fin.FD_outputC("returnstring", enforce_detg_constraint_symb_expressions,
                                                 params="outCverbose=False,preindent=0,includebraces=False")

        with open(os.path.join(outdir,"enforcedetgammabar_constraint_FD_order_"+str(FD_order)+".h"), "w") as file:
            file.write(lp.loop(["i2","i1","i0"],["0", "0", "0"],
                               ["cctk_lsh[2]","cctk_lsh[1]","cctk_lsh[0]"],
                               ["1","1","1"],
                                ["#pragma omp parallel for",
                                     "#include \"rfm_files/rfm_struct__read2.h\"",
                                     "#include \"rfm_files/rfm_struct__read1.h\""],"",
                                     "#include \"rfm_files/rfm_struct__read0.h\"\n"+enforce_gammadet_string))
        end = time.time()
        print("Finished gamma constraint C codegen (FD_order="+str(FD_order)+") in " + str(end - start) + " seconds.")
Beispiel #23
0
def declarerank3(objname, symmetry_option, DIM=-1):
    if DIM==-1:
        DIM = par.parval_from_str("DIM")
    IDX_OBJ_TMP = [[[sp.sympify(objname + str(i) + str(j) + str(k)) for k in range(DIM)] for j in range(DIM)] for i in range(DIM)]
    for i in range(DIM):
        for j in range(DIM):
            for k in range(DIM):
                if symmetry_option == "sym01":
                    if j < i:
                        IDX_OBJ_TMP[i][j][k] = IDX_OBJ_TMP[j][i][k]
                if symmetry_option == "sym12":
                    if k < j:
                        IDX_OBJ_TMP[i][j][k] = IDX_OBJ_TMP[i][k][j]
                if not (symmetry_option == "sym01" or symmetry_option == "sym12" or symmetry_option == "nosym"):
                    print("Error: symmetry option " + symmetry_option + " unsupported.")
                    sys.exit(1)
    return apply_symmetry_condition_to_derivatives(IDX_OBJ_TMP)
def register_C_functions_and_NRPy_basic_defines(NGHOSTS_account_for_onezone_upwind=False, enable_SIMD=True):
    # First register C functions needed by finite_difference

    # Then set up the dictionary entry for finite_difference in NRPy_basic_defines
    NGHOSTS = int(par.parval_from_str("finite_difference::FD_CENTDERIVS_ORDER")/2)
    if NGHOSTS_account_for_onezone_upwind:
        NGHOSTS += 1
    Nbd_str = """
// Set the number of ghost zones
// Note that upwinding in e.g., BSSN requires that NGHOSTS = FD_CENTDERIVS_ORDER/2 + 1 <- Notice the +1.
"""
    Nbd_str += "#define NGHOSTS " + str(NGHOSTS)+"\n"
    if not enable_SIMD:
        Nbd_str += """
// When enable_SIMD = False, this is the UPWIND_ALG() macro:
#define UPWIND_ALG(UpwindVecU) UpwindVecU > 0.0 ? 1.0 : 0.0\n"""
    outC_NRPy_basic_defines_h_dict["finite_difference"] = Nbd_str
Beispiel #25
0
def declarerank2(objname, symmetry_option, DIM=-1):
    if DIM==-1:
        DIM = par.parval_from_str("DIM")
    IDX_OBJ_TMP = [[sp.sympify(objname + str(i) + str(j)) for j in range(DIM)] for i in range(DIM)]
    for i in range(DIM):
        for j in range(DIM):
            if symmetry_option == "sym01":
                if (j < i):
                    # j<i in g_{ij} would indicate, e.g., g_{21}.
                    #  By this convention, we must set
                    #  g_{21} = g_{12}:
                    IDX_OBJ_TMP[i][j] = IDX_OBJ_TMP[j][i]
            elif symmetry_option == "nosym":
                pass
            else:
                print("Error: symmetry option " + symmetry_option + " unsupported.")
                sys.exit(1)
    return apply_symmetry_condition_to_derivatives(IDX_OBJ_TMP)
Beispiel #26
0
def register_gridfunctions_for_single_rank1(gf_type,gf_basename, DIM=-1, f_infinity=0.0, wavespeed=1.0):
    # Step 0: Verify the gridfunction basename is valid:
    gri.verify_gridfunction_basename_is_valid(gf_basename)

    # Step 1: Declare a list of SymPy variables,
    #         where IDX_OBJ_TMP[i] = gf_basename+str(i)
    IDX_OBJ_TMP = declarerank1(gf_basename, DIM)

    # Step 2: Register each gridfunction
    if DIM==-1:
        DIM = par.parval_from_str("DIM")
    gf_list = []
    for i in range(DIM):
        gf_list.append(str(IDX_OBJ_TMP[i]))
    gri.register_gridfunctions(gf_type, gf_list, rank=1, is_indexed=True, DIM=DIM, f_infinity=f_infinity, wavespeed=wavespeed)

    # Step 3: Return array of SymPy variables
    return IDX_OBJ_TMP
def output_hermite_interpolator_functions_h(path=os.path.join(".")):
    with open(os.path.join(path, "hermite_interpolator_functions.h"),
              "w") as file:
        file.write("""
#ifndef __HI_FUNCTIONS_H__
#define __HI_FUNCTIONS_H__
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
""")
        UNUSED = "__attribute__((unused))"
        NOINLINE = "__attribute__((noinline))"
        if par.parval_from_str("grid::GridFuncMemAccess") == "ETK":
            UNUSED = "CCTK_ATTRIBUTE_UNUSED"
            NOINLINE = "CCTK_ATTRIBUTE_NOINLINE"
        file.write("#define _UNUSED   " + UNUSED + "\n")
        file.write("#define _NOINLINE " + NOINLINE + "\n")

        for key, item in outC_function_dict.items():
            if "__HI_OPERATOR_FUNC__" in item:
                file.write(
                    item.replace(
                        "const REAL_SIMD_ARRAY _NegativeOne_ =",
                        "const REAL_SIMD_ARRAY " + UNUSED + " _NegativeOne_ =")
                )  # Many of the NegativeOne's get optimized away in the SIMD postprocessing step. No need for all the warnings

        # Clear all HI functions from outC_function_dict after outputting to hermite_interpolator_functions.h.
        #   Otherwise outputC will be outputting these as separate individual C codes & attempting to build them in Makefile.
        key_list_del = []
        element_del = []
        for i, func in enumerate(outC_function_master_list):
            if "__HI_OPERATOR_FUNC__" in func.desc:
                if func.name not in key_list_del:
                    key_list_del += [func.name]
                if func not in element_del:
                    element_del += [func]
        for func in element_del:
            outC_function_master_list.remove(func)
        for key in key_list_del:
            outC_function_dict.pop(key)
            if key in outC_function_prototype_dict:
                outC_function_prototype_dict.pop(key)
        file.write("#endif // #ifndef __HI_FUNCTIONS_H__\n")
Beispiel #28
0
    def BSSN_constraints__generate_symbolic_expressions_and_C_code():
        ######################################
        # START: GENERATE SYMBOLIC EXPRESSIONS
        # Define the Hamiltonian constraint and output the optimized C code.
        import BSSN.BSSN_constraints as bssncon

        bssncon.BSSN_constraints(add_T4UUmunu_source_terms=False)
        if T4UU != None:
            import BSSN.BSSN_stress_energy_source_terms as Bsest
            Bsest.BSSN_source_terms_for_BSSN_RHSs(T4UU)
            Bsest.BSSN_source_terms_for_BSSN_constraints(T4UU)
            bssncon.H += Bsest.sourceterm_H
            for i in range(3):
                bssncon.MU[i] += Bsest.sourceterm_MU[i]
        # END: GENERATE SYMBOLIC EXPRESSIONS
        ######################################

        # Store original finite-differencing order:
        FD_order_orig = par.parval_from_str("finite_difference::FD_CENTDERIVS_ORDER")
        # Set new finite-differencing order:
        par.set_parval_from_str("finite_difference::FD_CENTDERIVS_ORDER", FD_order)

        start = time.time()
        print("Generating optimized C code for Ham. & mom. constraints. May take a while, depending on CoordSystem.")
        Ham_mom_string = fin.FD_outputC("returnstring",
                                        [lhrh(lhs=gri.gfaccess("aux_gfs", "H"),   rhs=bssncon.H),
                                         lhrh(lhs=gri.gfaccess("aux_gfs", "MU0"), rhs=bssncon.MU[0]),
                                         lhrh(lhs=gri.gfaccess("aux_gfs", "MU1"), rhs=bssncon.MU[1]),
                                         lhrh(lhs=gri.gfaccess("aux_gfs", "MU2"), rhs=bssncon.MU[2])],
                                        params="outCverbose=False")

        with open(os.path.join(outdir,"BSSN_constraints_enable_Tmunu_"+str(enable_stress_energy_source_terms)+"_FD_order_"+str(FD_order)+".h"), "w") as file:
            file.write(lp.loop(["i2","i1","i0"],["cctk_nghostzones[2]","cctk_nghostzones[1]","cctk_nghostzones[0]"],
           ["cctk_lsh[2]-cctk_nghostzones[2]","cctk_lsh[1]-cctk_nghostzones[1]","cctk_lsh[0]-cctk_nghostzones[0]"],
                               ["1","1","1"],["#pragma omp parallel for","",""], "", Ham_mom_string))

        # Restore original finite-differencing order:
        par.set_parval_from_str("finite_difference::FD_CENTDERIVS_ORDER", FD_order_orig)

        end = time.time()
        print("(BENCH) Finished Hamiltonian & momentum constraint C codegen (FD_order="+str(FD_order)+",Tmunu="+str(enable_stress_energy_source_terms)+") in " + str(end - start) + " seconds.")
def EigenCoord_xx_to_Cart(i012suffix = ""):
    # Step 1: Find the Eigen-Coordinate and set up the Eigen-Coordinate's reference metric:
    CoordSystem_orig = par.parval_from_str("reference_metric::CoordSystem")
    par.set_parval_from_str("reference_metric::CoordSystem",rfm.get_EigenCoord())
    rfm.reference_metric()

    # Step 2: Output C code for the Eigen-Coordinate mapping from xx->Cartesian:
    outstr = """    {
      // xx_to_Cart for EigenCoordinate """+rfm.get_EigenCoord()+r""" (orig coord = """+CoordSystem_orig+r"""):
      REAL xx0 = xx[0][i0"""+i012suffix+"""];
      REAL xx1 = xx[1][i1"""+i012suffix+"""];
      REAL xx2 = xx[2][i2"""+i012suffix+"""];\n"""+ \
    outputC([rfm.xx_to_Cart[0],rfm.xx_to_Cart[1],rfm.xx_to_Cart[2]],
            ["xCart[0]","xCart[1]","xCart[2]"],
            "returnstring", params="preindent=3")+"    }\n"

    # Step 3: Restore reference_metric::CoordSystem back to the original CoordSystem
    par.set_parval_from_str("reference_metric::CoordSystem",CoordSystem_orig)
    rfm.reference_metric()

    # Step 4: Return EigenCoord xx_to_Cart C code
    return outstr
Beispiel #30
0
def print_msg_with_timing(desc,
                          msg="Symbolic",
                          startstop="start",
                          starttime=0.0):
    CoordSystem = par.parval_from_str("reference_metric::CoordSystem")
    elapsed = time.time() - starttime
    if msg == "Symbolic":
        if startstop == "start":
            print("Generating symbolic expressions for " + desc +
                  " (%s coords)..." % CoordSystem)
            return time.time()
        else:
            print("Finished generating symbolic expressions for " + desc +
                  " (%s coords) in %.1f seconds. Next up: C codegen..." %
                  (CoordSystem, elapsed))
    elif msg == "Ccodegen":
        if startstop == "start":
            print("Generating C code for " + desc +
                  " (%s coords)..." % CoordSystem)
            return time.time()
        else:
            print("Finished generating C code for " + desc +
                  " (%s coords) in %.1f seconds." % (CoordSystem, elapsed))