Exemplo n.º 1
0
        def tail(self, t, it, logger):
            cc = self.cc
            pv = self.pv

            # Get div(v) locally
            div_v = self.div_v
            if div_v is not None:
                div_v.assign(
                    df.project(df.div(pv["v"]), div_v.function_space()))

            # Compute required functionals
            keys = ["t", "E_kin", "Psi", "mean_p"]
            vals = {}
            vals[keys[0]] = t
            vals[keys[1]] = df.assemble(0.5 * cc["rho"] *
                                        df.inner(pv["v"], pv["v"]) * df.dx)
            vals[keys[2]] = df.assemble((
                  0.25 * cc["a"] * cc["eps"] *\
                    df.inner(df.dot(cc["LA"], df.grad(pv["phi"])), df.grad(pv["phi"]))
                + (cc["b"] / cc["eps"]) * cc["F"]
            ) * df.dx)
            vals[keys[3]] = df.assemble(pv["p"] * df.dx)
            if it % self.mod == 0:
                for key in keys:
                    self.functionals[key].append(vals[key])
            # Logging and reporting
            df.info("")
            df.begin("Reported functionals:")
            for key in keys[1:]:
                desc = "{:6s} = %g".format(key)
                logger.info(desc, (vals[key], ), (key, ), t)
            df.end()
            df.info("")
Exemplo n.º 2
0
    def _create_coefficients(r_dens, r_visc):
        c = OrderedDict()
        c[r"r_dens"] = r_dens
        c[r"r_visc"] = r_visc

        # Problem parameters
        c[r"\rho_1"] = 1.0
        c[r"\rho_2"] = r_dens * c[r"\rho_1"]
        c[r"\nu_1"] = 1.0
        c[r"\nu_2"] = r_visc * c[r"\nu_1"]
        c[r"\eps"] = 0.1
        c[r"g_a"] = 1.0

        # Characteristic quantities
        c[r"L_0"] = 1.0
        c[r"V_0"] = 1.0
        c[r"\rho_0"] = c[r"\rho_1"]

        df.begin("\nDimensionless numbers")
        At = (c[r"\rho_1"] - c[r"\rho_2"]) / (c[r"\rho_1"] + c[r"\rho_2"])
        Re_1 = c[r"\rho_1"] / c[r"\nu_1"]
        Re_2 = c[r"\rho_2"] / c[r"\nu_2"]
        df.info("r_dens = {}".format(r_dens))
        df.info("r_visc = {}".format(r_visc))
        df.info("Re_1 = {}".format(Re_1))
        df.info("Re_2 = {}".format(Re_2))
        df.info("At = {}".format(At))
        df.end()

        return c
Exemplo n.º 3
0
    def _load_from_file(cls, h5name, h5group, comm):

        df.begin(LogLevel.PROGRESS, "Load mesh from h5 file")
        geo = load_geometry_from_h5(h5name,
                                    h5group,
                                    include_sheets=False,
                                    comm=comm)
        df.end()

        f0 = get_attribute(geo, "f0", "fiber", None)
        s0 = get_attribute(geo, "s0", "sheet", None)
        n0 = get_attribute(geo, "n0", "sheet_normal", None)

        c0 = get_attribute(geo, "c0", "circumferential", None)
        r0 = get_attribute(geo, "r0", "radial", None)
        l0 = get_attribute(geo, "l0", "longitudinal", None)

        vfun = get_attribute(geo, "vfun", None)
        ffun = get_attribute(geo, "ffun", None)
        cfun = get_attribute(geo, "cfun", "sfun", None)

        kwargs = {
            "mesh": geo.mesh,
            "markers": geo.markers,
            "markerfunctions": MarkerFunctions2D(vfun=vfun,
                                                 ffun=ffun,
                                                 cfun=cfun),
            "microstructure": Microstructure(f0=f0, s0=s0, n0=n0),
            "crl_basis": CRLBasis(c0=c0, r0=r0, l0=l0),
        }

        return kwargs
 def time_step(self, rhs):
     dfn.begin("Computing velocity correction")
     if params['all_steps_adaptive']:
         self.adaptive_step(rhs)
     else:
         [bc.apply(self.A, rhs) for bc in self.bcs]
         dfn.solve(self.A, self.cur_vel.vector(), rhs, "cg", "amg")
     dfn.end()
Exemplo n.º 5
0
def log(level, msg):
    """Write a message to the logger.

    Parameters
    ----------
    level : int
        Log level of the message.
    msg : str
        Log message.
    """
    df.begin(level, msg)
    df.end()
Exemplo n.º 6
0
    def copy(self, deepcopy=False):
        """Returns a copy of self.

        Parameters
        ----------
        deepcopy : bool
            True if copy should be deep, default False.
        """
        msg = "Copying geometry"
        if deepcopy:
            msg += " with deepcopy."
        df.begin(LogLevel.DEBUG, msg)
        cp = self.__class__(**self._copy(deepcopy))
        df.end()
        return cp
Exemplo n.º 7
0
  def solve(self, flag):
    """
    :param flag : "p" to plot
    """
    
    nSteps = 20 

    for i in range(nSteps):
      try:
        self.solver.solve()
      except RuntimeError as message:
        print message
        d.end()
        response = raw_input('Press ENTER to continue ("q" to quit) ')
        if response == 'q': sys.exit()
      
      self.plot(i)
      self.update_mesh()
Exemplo n.º 8
0
    def save(self,
             h5name,
             h5group="",
             other_functions=None,
             other_attributes=None,
             overwrite_file=False,
             overwrite_group=True):
        """Saves a geometry to a h5 file.

        Parameters
        ----------
        h5name : str
            The location and name of the output file without file extension.
        h5group : str
            The h5 group of the geometry.
        other_functions :
            Extra mesh functions.
        other_attributes :
            Extra mesh attributes.
        overwrite_file : bool
            True if existing file should be overwritten.
        overwrite_group : bool
            True if existing group should be overwritten.
        """

        df.begin(LogLevel.PROGRESS, "Saving geometry to {}...".format(h5name))
        save_geometry_to_h5(
            self.mesh,
            h5name,
            h5group=h5group,
            markers=self.markers,
            markerfunctions=namedtuple_as_dict(self.markerfunctions),
            microstructure=namedtuple_as_dict(self.microstructure),
            local_basis=namedtuple_as_dict(self.crl_basis),
            overwrite_file=overwrite_file,
            overwrite_group=overwrite_group)
        df.end()
Exemplo n.º 9
0
def check_h5group(h5name, h5group, delete=False, comm=mpi_comm_world):

    if not isinstance(h5group, str):
        msg = "Error! h5group has to be of type string. Your h5group is of type {}".format(
            type(h5group))
        raise TypeError(msg)

    h5group_in_h5file = False
    if not os.path.isfile(h5name):
        return False

    filemode = "a" if delete else "r"
    if not os.access(h5name, os.W_OK):
        filemode = "r"
        if delete:
            df.begin(
                df.LogLevel.WARNING, "You do not have write access to file "
                "{}".format(h5name))
            delete = False
            df.end()

    with open_h5py(h5name, filemode, comm) as h5file:
        if h5group in h5file:
            h5group_in_h5file = True
            if delete:
                if parallel_h5py:
                    df.begin(
                        df.LogLevel.DEBUG, "Deleting existing group: "
                        "'{}'".format(h5group))
                    del h5file[h5group]
                    df.end()

                else:
                    if df.MPI.rank(comm) == 0:
                        df.begin(
                            df.LogLevel.DEBUG, "Deleting existing group: "
                            "'{}'".format(h5group))
                        del h5file[h5group]
                        df.end()

    return h5group_in_h5file
Exemplo n.º 10
0
    def solve(self):
        """
        Perform one solution step (in time).
        """
        solver = self.data["solver"]
        begin("Advance-phase")
        for i, A in enumerate(self.data["A"]["chi"]):
            b = assemble(self.data["rhs"]["chi"][i])
            solver["chi"].solve(A, self.data["sol"]["chi"][i].vector(), b)
        for i, A in enumerate(self.data["A"]["phi"]):
            b = assemble(self.data["rhs"]["phi"][i])
            solver["phi"].solve(A, self.data["sol"]["phi"][i].vector(), b)
        end()

        begin("Pressure step")
        b = assemble(self.data["rhs"]["p"])
        for bc in self.data["bcs"].get("p", []):
            bc.apply(b)
        if self._flags["fix_p"]:
            # Orthogonalize RHS vector b with respect to the null space
            self.data["null_space"].orthogonalize(b)

        solver["p"].solve(self.data["A"]["p"], self.data["sol"]["p"].vector(),
                          b)

        if self._flags["fix_p"]:
            self._calibrate_pressure(self.data["sol"]["p"],
                                     self.data["null_fcn"])
        end()

        begin("Velocity step")
        for i, A in enumerate(self.data["A"]["v"]):
            b = assemble(self.data["rhs"]["v"][i])
            # FIXME: How to apply bcs in a symmetric fashion?
            for bc in self.data["bcs"].get("v", []):
                if bc[i] is not None:
                    bc[i].apply(b)
            solver["v"].solve(A, self.data["sol"]["v"][i].vector(), b)
        end()
Exemplo n.º 11
0
def test_karman(num_steps=2, lcar=0.1, show=False):
    mesh = create_mesh(lcar)

    W_element = VectorElement('Lagrange', mesh.ufl_cell(), 2)
    P_element = FiniteElement('Lagrange', mesh.ufl_cell(), 1)
    WP = FunctionSpace(mesh, W_element * P_element)

    W = WP.sub(0)
    # P = WP.sub(1)

    mesh_eps = 1.0e-12

    # Define mesh and boundaries.
    # pylint: disable=no-self-use
    class LeftBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[0] < x0 + mesh_eps

    left_boundary = LeftBoundary()

    class RightBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[0] > x1 - mesh_eps

    right_boundary = RightBoundary()

    class LowerBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[1] < y0 + mesh_eps

    lower_boundary = LowerBoundary()

    class UpperBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[1] > y1 - mesh_eps

    upper_boundary = UpperBoundary()

    class ObstacleBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return (on_boundary and x0 + mesh_eps < x[0] < x1 - mesh_eps
                    and y0 + mesh_eps < x[1] < y1 - mesh_eps)

    obstacle_boundary = ObstacleBoundary()

    # Boundary conditions for the velocity.
    # Proper inflow and outflow conditions are a matter of voodoo. See for
    # example Gresho/Sani, or
    #
    #     Boundary conditions for open boundaries for the incompressible
    #     Navier-Stokes equation;
    #     B.C.V. Johansson;
    #     J. Comp. Phys. 105, 233-251 (1993).
    #
    # The latter in particularly suggest for the inflow:
    #
    #     u = u0,
    #     d^r v / dx^r = v_r,
    #     div(u) = 0,
    #
    # where u and v are the velocities in normal and tangential directions,
    # respectively, and r\in{0,1,2}. The setting r=0 essentially means to set
    # (u,v) statically at the left boundary, r=1 means to set u and control
    # dv/dn, which is what we do here (namely implicitly by dv/dn=0).
    # At the outflow,
    #
    #     d^j u / dx^j = 0,
    #     d^q v / dx^q = 0,
    #     p = p0,
    #
    # is suggested with j=q+1. Choosing q=0, j=1 means setting the tangential
    # component of the outflow to 0, and letting the normal component du/dn=0
    # (again, this is achieved implicitly by the weak formulation).
    #
    inflow = Expression('%e * (%e - x[1]) * (x[1] - %e) / %e' %
                        (entrance_velocity, y1, y0, (0.5 * (y1 - y0))**2),
                        degree=2)
    outflow = Expression('%e * (%e - x[1]) * (x[1] - %e) / %e' %
                         (entrance_velocity, y1, y0, (0.5 * (y1 - y0))**2),
                         degree=2)
    u_bcs = [
        DirichletBC(W, (0.0, 0.0), upper_boundary),
        DirichletBC(W, (0.0, 0.0), lower_boundary),
        DirichletBC(W, (0.0, 0.0), obstacle_boundary),
        DirichletBC(W.sub(0), inflow, left_boundary),
        #
        DirichletBC(W.sub(0), outflow, right_boundary),
    ]
    # dudt_bcs = [
    #     DirichletBC(W, (0.0, 0.0), upper_boundary),
    #     DirichletBC(W, (0.0, 0.0), lower_boundary),
    #     DirichletBC(W, (0.0, 0.0), obstacle_boundary),
    #     DirichletBC(W.sub(0), 0.0, left_boundary),
    #     # DirichletBC(W.sub(1), 0.0, right_boundary),
    #     ]

    # If there is a penetration boundary (i.e., n.u!=0), then the pressure must
    # be set somewhere to make sure that the Navier-Stokes problem remains
    # consistent.
    # When solving Stokes with no Dirichlet conditions whatsoever, the pressure
    # tends to 0 at the outlet. This is natural since there, the liquid can
    # flow out at the rate it needs to be under no pressure at all.
    # Hence, at outlets, set the pressure to 0.
    p_bcs = [
        # DirichletBC(P, 0.0, right_boundary)
    ]

    # Getting vortices is not easy. If we take the actual viscosity of water,
    # they don't appear.
    mu = 0.002
    # mu = materials.water.dynamic_viscosity(T=293.0)

    # For starting off, solve the Stokes equation.
    u0, p0 = flow.stokes.solve(WP,
                               u_bcs + p_bcs,
                               mu,
                               f=Constant((0.0, 0.0)),
                               verbose=False,
                               tol=1.0e-13,
                               max_iter=10000)
    u0.rename('velocity', 'velocity')
    p0.rename('pressure', 'pressure')

    rho = materials.water.density(T=293.0)
    # stepper = flow.navier_stokes.Chorin()
    # stepper = flow.navier_stokes.IPCS()
    stepper = flow.navier_stokes.Rotational()

    W2 = u0.function_space()
    P2 = p0.function_space()
    u_bcs = [
        DirichletBC(W2, (0.0, 0.0), upper_boundary),
        DirichletBC(W2, (0.0, 0.0), lower_boundary),
        DirichletBC(W2, (0.0, 0.0), obstacle_boundary),
        DirichletBC(W2.sub(0), inflow, left_boundary),
        #
        DirichletBC(W2.sub(0), outflow, right_boundary),
    ]
    # TODO settting the outflow _and_ the pressure at the outlet is actually
    #      not necessary. Even without the pressure Dirichlet conditions, the
    #      pressure correction system should be consistent.
    p_bcs = [DirichletBC(P2, 0.0, right_boundary)]

    # Report Reynolds number.
    # https://en.wikipedia.org/wiki/Reynolds_number#Sphere_in_a_fluid
    reynolds = entrance_velocity * obstacle_diameter * rho / mu
    print('Reynolds number:  %e' % reynolds)

    dt = 1.0e-5
    dt_max = 1.0
    t = 0.0

    with XDMFFile(mpi_comm_world(), 'karman.xdmf') as xdmf_file:
        xdmf_file.parameters['flush_output'] = True
        xdmf_file.parameters['rewrite_function_mesh'] = False

        k = 0
        while k < num_steps:
            k += 1
            print()
            print('t = %f' % t)
            if show:
                plot(u0)
                plot(p0)
                xdmf_file.write(u0, t)
                xdmf_file.write(p0, t)

            u1, p1 = stepper.step(Constant(dt), {0: u0},
                                  p0,
                                  u_bcs,
                                  p_bcs,
                                  Constant(rho),
                                  Constant(mu),
                                  f={
                                      0: Constant((0.0, 0.0)),
                                      1: Constant((0.0, 0.0))
                                  },
                                  verbose=False,
                                  tol=1.0e-10)
            u0.assign(u1)
            p0.assign(p1)

            # Adaptive stepsize control based solely on the velocity field.
            # CFL-like condition for time step. This should be some sort of
            # average of the temperature in the current step and the target
            # step.
            #
            # More on step-size control for Navier--Stokes:
            #
            #     Adaptive time step control for the incompressible
            #     Navier-Stokes equations;
            #     Volker John, Joachim Rang;
            #     Comput. Methods Appl. Mech. Engrg. 199 (2010) 514-524;
            #     <http://www.wias-berlin.de/people/john/ELECTRONIC_PAPERS/JR10.CMAME.pdf>.
            #
            # Section 3.3 in that paper notes that time-adaptivity for theta-
            # schemes is too costly. They rather reside to DIRK- and
            # Rosenbrock-methods.
            #
            begin('Step size adaptation...')
            ux, uy = u0.split()
            unorm = project(sqrt(ux**2 + uy**2),
                            FunctionSpace(mesh, 'Lagrange', 2),
                            form_compiler_parameters={'quadrature_degree': 4})
            unorm = norm(unorm.vector(), 'linf')

            # print('||u||_inf = %e' % unorm)
            # Some smooth step-size adaption.
            target_dt = 1.0 * mesh.hmax() / unorm
            print('current dt: %e' % dt)
            print('target dt:  %e' % target_dt)
            # alpha is the aggressiveness factor. The distance between the
            # current step size and the target step size is reduced by
            # |1-alpha|. Hence, if alpha==1 then dt_next==target_dt. Otherwise
            # target_dt is approached more slowly.
            alpha = 0.5
            dt = min(
                dt_max,
                # At most double the step size from step to step.
                dt * min(2.0, 1.0 + alpha * (target_dt - dt) / dt))
            print('next dt:    %e' % dt)
            t += dt
            end()

    return
Exemplo n.º 12
0
    def solve(self):
        """
        Perform one solution step (in time).
        """
        begin("Cahn-Hilliard step")
        self.iters["CH"][-1] = self.data["solver"]["CH"]["nln"].solve(
            self.data["problem_ch"], self.data["sol_ch"].vector())[0]
        self.iters["CH"][0] += self.iters["CH"][-1]
        end()

        begin("Navier-Stokes step")
        # Update stabilization terms
        if self.data["model"].parameters["semi"]["sdstab"]:
            self.data["model"]._update_sd_stab_parameter()

        pcd_assembler = self.data.get("pcd_assembler", None)
        if pcd_assembler:
            # Symmetric assembly of the linear system
            A, b = PETScMatrix(self.comm()), PETScVector(self.comm())
            pcd_assembler.system_matrix(A)
            pcd_assembler.rhs_vector(b)
        else:
            # Standard assembly of the linear system
            A = assemble(self.data["forms"]["lin"]["lhs"])
            b = assemble(self.data["forms"]["lin"]["rhs"])
            for bc in self.data["bcs_ns"]:
                bc.apply(A, b)

        if self._flags["fix_p"]:
            # Attach null space to PETSc matrix
            as_backend_type(A).set_nullspace(self.data["null_space"])
            # Orthogonalize RHS vector b with respect to the null space
            self.data["null_space"].orthogonalize(b)

        if pcd_assembler:
            # Symmetric assembly of the preconditioner
            P = PETScMatrix(self.comm())
            pcd_assembler.pc_matrix(P)
            # FIXME: Should we attach the null space also to preconditioner?
            #        Probably not as 'set_nullspace' is related to KSP (not PC).
            # if P.empty():
            #     P = A
            # else:
            #     as_backend_type(P).set_nullspace(self.data["null_space"])
            P = A if P.empty() else P
            # Standard assembly of the preconditioner matrix
            # if self.data["forms"]["pcd"]["a_pc"] is not None:
            #     P = assemble(self.data["forms"]["pcd"]["a_pc"])
            #     for bc in self.data["bcs_ns"]:
            #         bc.apply(P)
            # else:
            #     P = A
            self.data["solver"]["NS"].set_operators(A, P)
            if not self._flags["init_pcd_called"]:  # only one call is allowed
                self.data["solver"]["NS"].init_pcd(pcd_assembler)
                self._flags["init_pcd_called"] = True
        else:
            # FIXME: Here we assume that LU solver is used
            assert self.data["solver"]["NS"].parameter_type() == 'lu_solver'
            self.data["solver"]["NS"].set_operator(A)
            # NOTE: Preconditioner matrix can't be set for LUSolver.

        self.iters["NS"][-1] = \
          self.data["solver"]["NS"].solve(self.data["sol_ns"].vector(), b)
        info("Navier-Stokes solver finished in {} iterations".format(
            self.iters["NS"][-1]))
        self.iters["NS"][0] += self.iters["NS"][-1]

        if self._flags["fix_p"]:
            self._calibrate_pressure(self.data["sol_ns"],
                                     self.data["null_fcn"])
        end()
Exemplo n.º 13
0
def save_geometry_to_h5(mesh,
                        h5name,
                        h5group="",
                        markers=None,
                        markerfunctions={},
                        microstructure={},
                        local_basis={},
                        comm=mpi_comm_world,
                        other_functions={},
                        other_attributes={},
                        overwrite_file=False,
                        overwrite_group=True):
    """
    Save geometry and other geometrical functions to a HDF file.

    Parameters
    ----------
    mesh : :class:`dolfin.mesh`
        The mesh
    h5name : str
        Path to the file
    h5group : str
        Folder within the file. Default is "" which means in
        the top folder.
    markers : dict
        A dictionary with markers. See `get_markers`.
    fields : list
        A list of functions for the microstructure
    local_basis : list
        A list of functions for the crl basis
    meshfunctions : dict
        A dictionary with keys being the dimensions the the values
        beeing the meshfunctions.
    comm : :class:`dolfin.MPI`
        MPI communicator
    other_functions : dict
        Dictionary with other functions you want to save
    other_attributes: dict
        Dictionary with other attributes you want to save
    overwrite_file : bool
        If true, and the file exists, the file will be overwritten (default: False)
    overwrite_group : bool
        If true and h5group exist, the group will be overwritten.

    """
    h5name = os.path.splitext(h5name)[0] + ".h5"

    assert isinstance(mesh, Mesh)

    file_mode = "a" if os.path.isfile(h5name) and not overwrite_file else "w"

    # IF we should append the file but overwrite the group we need to
    # check that the group does not exist. If so we need to open it in
    # h5py and delete it.
    if file_mode == "a" and overwrite_group and h5group != "":
        check_h5group(h5name, h5group, delete=True, comm=comm)

    with HDF5File(comm, h5name, file_mode) as h5file:

        # Save mesh
        ggroup = "{}/geometry".format(h5group)
        mgroup = "{}/mesh".format(ggroup)
        h5file.write(mesh, mgroup)

        # Save markerfunctions
        df.begin(LogLevel.PROGRESS, "Saving marker functions.")
        for dim, key in enumerate(markerfunctions.keys()):
            mf = markerfunctions[key]
            if mf is not None:
                dgroup = "{}/mesh/meshfunction_{}".format(ggroup, dim)
                h5file.write(mf, dgroup)
        df.end()

        # Save markers
        df.begin(LogLevel.PROGRESS, "Saving markers.")
        for name, (marker, dim) in markers.items():
            for key_str in ["domain", "meshfunction"]:
                dgroup = "{}/mesh/{}_{}".format(ggroup, key_str, dim)

                if h5file.has_dataset(dgroup):
                    aname = "marker_name_{}".format(name)
                    h5file.attributes(dgroup)[aname] = marker
        df.end()

        # Save microstructure
        df.begin(LogLevel.PROGRESS, "Saving microstructure.")
        for key in microstructure.keys():
            ms = microstructure[key]
            if ms is not None:
                fgroup = "{}/microstructure".format(h5group)
                fsubgroup = "{}/{}".format(fgroup, key)
                h5file.write(microstructure[key], fsubgroup)
                h5file.attributes(fsubgroup)["name"] = key
                elm = ms.function_space().ufl_element()

        try:
            family, degree = elm.family(), elm.degree()
            fspace = "{}_{}".format(family, degree)
            h5file.attributes(fgroup)["space"] = fspace
            h5file.attributes(fgroup)["names"] = ":".join(
                microstructure.keys())
        except:
            pass
        df.end()

        # Save local basis
        df.begin(LogLevel.PROGRESS, "Saving local basis.")
        for key in local_basis.keys():
            ml = local_basis[key]
            if ml is not None:
                lgroup = "{}/local basis functions".format(h5group)
                h5file.write(ml, lgroup + "/{}".format(key))
                elm = ml.function_space().ufl_element()

        try:
            family, degree = elm.family(), elm.degree()
            lspace = "{}_{}".format(family, degree)
            h5file.attributes(lgroup)["space"] = lspace
            h5file.attributes(lgroup)["names"] = ":".join(local_basis.keys())
        except:
            pass
        df.end()

        # Save other functions
        df.begin(LogLevel.PROGRESS, "Saving other functions")
        for key in other_functions.keys():
            mo = other_functions[key]
            if mo is not None:
                fungroup = "/".join([h5group, key])
                h5file.write(mo, fungroup)
                elm = mo.function_space().ufl_element()

        try:
            family, degree, vsize = elm.family(), elm.degree(), elm.value_size(
            )
            fspace = "{}_{}".format(family, degree)
            h5file.attributes(fungroup)["space"] = fspace
            h5file.attributes(fungroup)["value_size"] = vsize
        except:
            pass
        df.end()

        # Save other attributes
        df.begin(LogLevel.PROGRESS, "Saving other attributes")
        for key in other_attributes:
            if isinstance(other_attributes[key], str) and isinstance(key, str):
                h5file.attributes(h5group)[key] = other_attributes[key]
            else:
                begin(
                    df.LogLevel.WARNING,
                    "Invalid attribute {} = {}".format(key,
                                                       other_attributes[key]))
                end()
        df.end()

    df.begin(df.LogLevel.INFO, "Geometry saved to {}".format(h5name))
    df.end()
Exemplo n.º 14
0
 def __exit__(self, tpe, value, traceback):
     end()
     return
Exemplo n.º 15
0
def compute_boussinesq(target_time, lcar, supg=False):
    mesh, hot_boundary, cool_boundary = create_mesh(lcar)

    room_temp = 293.0

    # Density depends on temperature.
    rho = materials.water.density
    # Take dynamic viscosity at room temperature.
    mu = materials.water.dynamic_viscosity(room_temp)
    cp = materials.water.specific_heat_capacity
    kappa = materials.water.thermal_conductivity

    # Start time, end time, time step.
    dt_max = 1.0
    dt0 = 1.0e-2
    # This should be
    # umax = 1.0e-1
    # dt0 = 0.2 * mesh.hmin() / umax
    t = 0.0

    max_heater_temp = 320.0

    # Gravity accelleration.
    accelleration_constant = -9.81
    g = Constant((0.0, accelleration_constant))

    W_element = VectorElement('Lagrange', mesh.ufl_cell(), 2)
    P_element = FiniteElement('Lagrange', mesh.ufl_cell(), 1)
    WP = FunctionSpace(mesh, W_element * P_element)

    Q = FunctionSpace(mesh, 'Lagrange', 2)

    # Everything at room temperature for starters
    theta0 = project(Constant(room_temp), Q)
    theta0.rename('temperature', 'temperature')

    u_bcs = [DirichletBC(WP.sub(0), (0.0, 0.0), 'on_boundary')]
    p_bcs = []

    # Solve Stokes for initial state.
    # Make sure that the right-hand side is the same as in the first step of
    # Navier-Stokes below. This avoids problems with the initial pressure being
    # a bit off, which leads to errors.
    # u0, p0 = flow.stokes.solve(
    #     WP,
    #     u_bcs + p_bcs,
    #     mu,
    #     f=rho(theta0) * g,
    #     verbose=False,
    #     tol=1.0e-15,
    #     max_iter=1000
    #     )
    y = SpatialCoordinate(mesh)[1]
    u0 = project(Constant([0, 0]), FunctionSpace(mesh, W_element))
    u0.rename('velocity', 'velocity')
    p0 = project(
        rho(theta0) * accelleration_constant * y,
        FunctionSpace(mesh, P_element))
    p0.rename('pressure', 'pressure')

    # div_u = Function(Q)
    dt = dt0

    with XDMFFile(mpi_comm_world(), 'boussinesq.xdmf') as xdmf_file:
        xdmf_file.parameters['flush_output'] = True
        xdmf_file.parameters['rewrite_function_mesh'] = False

        while t < target_time + DOLFIN_EPS:
            begin('Time step %e -> %e...' % (t, t + dt))

            # Crank up the heater from room_temp to max_heater_temp in t1 secs.
            t1 = 30.0
            heater_temp = (+room_temp + min(1.0, t / t1) *
                           (max_heater_temp - room_temp))
            # heater_temp = room_temp

            # Velocity and heat and connected by
            #
            #    theta1 = F_theta(u1, theta0)
            #    u1, p1 = F_u(u0, p0, theta1)
            #
            # One can either replace u1, theta1 on the right-hand side by u0,
            # theta0, respectively, or wrap the whole thing in a Banach
            # iteration 'a la
            #
            #    theta = F_theta(u_prev, theta0)
            #    (u, p) = F_u(u0, p0, theta_prev)
            #
            # and do that until the residuals are close to 0.
            u_prev = Function(u0.function_space())
            u_prev.assign(u0)

            theta_prev = Function(theta0.function_space())
            theta_prev.assign(theta0)
            is_banach_converged = False
            banach_tol = 1.0e-1
            max_banach_steps = 10
            target_banach_steps = 5
            banach_step = 0
            while not is_banach_converged:
                banach_step += 1
                if banach_step > max_banach_steps:
                    info('\nBanach solver failed to converge. '
                         'Decrease time step from %e to %e and try again.\n' %
                         (dt, 0.25 * dt))
                    dt *= 0.25
                    end()  # time step
                    break
                begin('Banach step %d:' % banach_step)
                # Do one heat time step.
                begin('Computing heat...')
                heat_bcs = [
                    DirichletBC(Q, heater_temp, hot_boundary),
                    DirichletBC(Q, room_temp, cool_boundary),
                ]
                # Use all quantities at room temperature to avoid nonlinearity
                stepper = parabolic.ImplicitEuler(
                    heat.Heat(Q,
                              u_prev,
                              kappa(room_temp),
                              rho(room_temp),
                              cp(room_temp),
                              heat_bcs,
                              Constant(0.0),
                              supg_stabilization=supg))

                theta1 = stepper.step(theta0, t, dt)
                end()

                # Do one Navier-Stokes time step.
                begin('Computing flux and pressure...')
                # stepper = flow.navier_stokes.Chorin()
                # stepper = flow.navier_stokes.IPCS()
                stepper = flow.navier_stokes.Rotational()
                W = u0.function_space()
                u_bcs = [DirichletBC(W, (0.0, 0.0), 'on_boundary')]
                p_bcs = []
                try:
                    u1, p1 = stepper.step(
                        Constant(dt),
                        {0: u0},
                        p0,
                        u_bcs,
                        p_bcs,
                        # TODO use rho(theta)
                        rho(room_temp),
                        Constant(mu),
                        f={
                            0: rho(theta_prev) * g,
                            1: rho(theta_prev) * g
                        },
                        verbose=False,
                        tol=1.0e-10)
                except RuntimeError:
                    info('Navier--Stokes solver failed to converge. '
                         'Decrease time step from %e to %e and try again.' %
                         (dt, 0.5 * dt))
                    dt *= 0.5
                    end()  # navier-stokes
                    end()  # banach step
                    end()  # time step
                    # http://stackoverflow.com/a/1859099/353337
                    break
                end()  # navier-stokes

                u1x, u1y = u1.split()
                uprevx, uprevy = u_prev.split()
                unorm = project(
                    abs(u1x - uprevx) + abs(u1y - uprevy),
                    Q,
                    form_compiler_parameters={'quadrature_degree': 4})
                u_diff_norm = norm(unorm.vector(), 'linf')

                theta_diff = Function(theta1.function_space())
                theta_diff.vector()[:] = theta1.vector() - theta_prev.vector()
                theta_diff_norm = norm(theta_diff.vector(), 'linf')

                info('Banach residuals:')
                info('   ||u - u_prev||         = %e' % u_diff_norm)
                info('   ||theta - theta_prev|| = %e' % theta_diff_norm)

                is_banach_converged = \
                    u_diff_norm < banach_tol and theta_diff_norm < banach_tol

                u_prev.assign(u1)
                theta_prev.assign(theta1)
                end()  # banach step
            else:
                # from dolfin import plot, interactive
                # plot(u0)
                # plot(p0)
                # u1.rename('u1', 'u1')
                # plot(u1)
                # p1.rename('p1', 'p1')
                # plot(p1)
                # interactive()

                # Assigning and plotting. We do that here so all methods have
                # access to `x` and `x_1`.
                theta0.assign(theta1)
                u0.assign(u1)
                p0.assign(p1)

                # write to file
                xdmf_file.write(theta0, t)
                xdmf_file.write(u0, t)
                xdmf_file.write(p0, t)

                # from dolfin import plot, interactive
                # plot(theta0, title='theta')
                # plot(u0, title='u')
                # # plot(div(u), title='div(u)', rescale=True)
                # plot(p0, title='p')
                # interactive()

                end()  # time step

                begin('\nStep size adaptation...')
                # Step-size control can be done purely based on the velocity
                # field; see
                #
                #     Adaptive time step control for the incompressible
                #     Navier-Stokes equations;
                #     Volker John, Joachim Rang;
                #     Comput. Methods Appl. Mech. Engrg. 199 (2010) 514-524;
                #     <http://www.wias-berlin.de/people/john/ELECTRONIC_PAPERS/JR10.CMAME.pdf>.
                #
                # Section 3.3 in that paper notes that time-adaptivity for
                # theta- schemes is too costly. They rather reside to DIRK- and
                # Rosenbrock- methods.
                #
                # Implementation:
                #   ux, uy = u0.split()
                #   unorm = project(
                #           abs(ux) + abs(uy),
                #           Q,
                #           form_compiler_parameters={'quadrature_degree': 4}
                #           )
                #   unorm = norm(unorm.vector(), 'linf')
                #   # print('||u||_inf = %e' % unorm)
                #   # Some smooth step-size adaption.
                #   target_dt = 0.2 * mesh.hmax() / unorm

                # In our case, step failures are almost always because Banach
                # didn't converge. Hence, design a step size adaptation based
                # on the Banach steps.
                target_dt = dt * target_banach_steps / banach_step

                info('current dt: %e' % dt)
                info('target dt:  %e' % target_dt)
                # alpha is the aggressiveness factor. The distance between the
                # current step size and the target step size is reduced by
                # |1-alpha|. Hence, if alpha==1 then dt_next==target_dt.
                # Otherwise target_dt is approached more slowly.
                alpha = 0.5
                dt = min(
                    dt_max,
                    # At most double the step size from step to step.
                    dt * min(2.0, 1.0 + alpha * (target_dt - dt) / dt))
                info('next dt:    %e\n' % dt)
                t += dt
                end()

    return u1, p1, theta1
Exemplo n.º 16
0
def test(problem, max_num_steps=2, show=False):
    # # Density depends on temperature.
    # material = 'water'
    # rho = params[material]['density'](293.0)
    # mu = params[material]['dynamic viscosity'](293.0)

    rho = 1.0
    mu = 1.0

    # Start time, end time, time step.
    t = 0.0
    T = 8.0
    dt = 1.0e-5
    dt_max = 1.0e-1

    num_subspaces = problem.W.num_sub_spaces()

    if num_subspaces == 2:
        # g = Constant((0.0, 0.0))
        g = Constant((0.0, -9.81))
    elif num_subspaces == 3:
        # g = Constant((0.0, 0.0, 0.0))
        g = Constant((0.0, -9.81, 0.0))
    else:
        raise RuntimeError("Illegal number of subspaces ({}).".format(num_subspaces))

    initial_stokes = False
    if initial_stokes:
        u0, p0 = cyl_stokes.solve(
            problem.W,
            problem.P,
            mu,
            rho,
            problem.u_bcs,
            problem.p_bcs,
            f=rho * g,
            tol=1.0e-10,
            maxiter=2000,
        )
    else:
        # Initial states.
        u0 = Function(problem.W, name="velocity")
        u0.vector().zero()
        p0 = Function(problem.P, name="pressure")
        p0.vector().zero()

    filename = "navier_stokes.xdmf"
    with XDMFFile(mpi_comm_world(), filename) as xdmf_file:
        xdmf_file.parameters["flush_output"] = True
        xdmf_file.parameters["rewrite_function_mesh"] = False

        if show:
            xdmf_file.write(u0, t)
            xdmf_file.write(p0, t)

        stepper = cyl_ns.IPCS(time_step_method="backward euler")
        steps = 0
        while t < T + DOLFIN_EPS and steps < max_num_steps:
            steps += 1
            begin("Time step {:e} -> {:e}...".format(t, t + dt))
            try:
                u1, p1 = stepper.step(
                    Constant(dt),
                    {0: u0},
                    p0,
                    problem.W,
                    problem.P,
                    problem.u_bcs,
                    problem.p_bcs,
                    Constant(rho),
                    Constant(mu),
                    f={0: rho * g, 1: rho * g},
                    tol=1.0e-10,
                )
            except RuntimeError:
                print(
                    "Navier--Stokes solver failed to converge. "
                    "Decrease time step from {} to {} and try again.".format(
                        dt, 0.5 * dt
                    )
                )
                dt *= 0.5
                end()
                end()
                end()
                continue

            u0.assign(u1)
            p0.assign(p1)

            if show:
                # Save to files.
                xdmf_file.write(u0, t + dt)
                xdmf_file.write(p0, t + dt)
                # Plotting for some reason takes up a lot of memory.
                plot(u0, title="velocity", rescale=True)
                plot(p0, title="pressure", rescale=True)
                # interactive()

            begin("Step size adaptation...")
            # unorm = project(abs(u[0]) + abs(u[1]) + abs(u[2]),
            #                 P,
            #                 form_compiler_parameters={'quadrature_degree': 4}
            #                 )
            unorm = project(
                norm(u1), problem.P, form_compiler_parameters={"quadrature_degree": 4}
            )
            unorm = norm(unorm.vector(), "linf")
            # print('||u||_inf = {:e}'.format(unorm))
            # Some smooth step-size adaption.
            target_dt = 0.2 * problem.mesh.hmax() / unorm
            print("current dt: {:e}".format(dt))
            print("target dt:  {:e}".format(target_dt))
            # alpha is the aggressiveness factor. The distance between the
            # current step size and the target step size is reduced by
            # |1-alpha|. Hence, if alpha==1 then dt_next==target_dt. Otherwise
            # target_dt is approached slowlier.
            alpha = 0.5
            dt = min(
                dt_max,
                # At most double the step size from step to step.
                dt * min(2.0, 1.0 + alpha * (target_dt - dt) / dt),
            )
            print("next dt:    {:e}".format(dt))
            t += dt
            end()
            end()
    return