Example #1
0
    def __init__(self, name, regions, dof_names, dof_map_fun, variables,
                 functions=None):
        Struct.__init__(self, name=name, regions=regions, dof_names=dof_names)

        if dof_map_fun is not None:
            self.dof_map_fun = get_condition_value(dof_map_fun, functions,
                                                   'LCBC', 'dof_map_fun')
        self._setup_dof_names(variables)
Example #2
0
    def __init__(self, name, regions, dof_names, dof_map_fun, shift_fun, variables, ts, functions):
        LCBCOperator.__init__(self, name, regions, dof_names, dof_map_fun, variables, functions=functions)

        self.shift_fun = get_condition_value(shift_fun, functions, "LCBC", "shift")

        mvar = variables[self.var_names[0]]
        svar = variables[self.var_names[1]]

        mfield = mvar.field
        sfield = svar.field

        nmaster = mfield.get_dofs_in_region(regions[0], merge=True)
        nslave = sfield.get_dofs_in_region(regions[1], merge=True)

        if nmaster.shape != nslave.shape:
            msg = "shifted EPBC node list lengths do not match!\n(%s,\n %s)" % (nmaster, nslave)
            raise ValueError(msg)

        mcoor = mfield.get_coor(nmaster)
        scoor = sfield.get_coor(nslave)

        i1, i2 = self.dof_map_fun(mcoor, scoor)
        self.mdofs = expand_nodes_to_equations(nmaster[i1], dof_names[0], self.all_dof_names[0])
        self.sdofs = expand_nodes_to_equations(nslave[i2], dof_names[1], self.all_dof_names[1])

        self.shift = self.shift_fun(ts, scoor[i2], regions[1])

        meq = mvar.eq_map.eq[self.mdofs]
        seq = svar.eq_map.eq[self.sdofs]

        # Ignore DOFs with EBCs or EPBCs.
        mia = nm.where(meq >= 0)[0]
        sia = nm.where(seq >= 0)[0]

        ia = nm.intersect1d(mia, sia)

        meq = meq[ia]
        seq = seq[ia]

        num = len(ia)

        ones = nm.ones(num, dtype=nm.float64)
        n_dofs = [variables.adi.n_dof[ii] for ii in self.var_names]
        mtx = sp.coo_matrix((ones, (meq, seq)), shape=n_dofs)

        self.mtx = mtx.tocsr()

        self.rhs = self.shift.ravel()[ia]

        self.ameq = meq
        self.aseq = seq

        self.n_mdof = len(nm.unique(meq))
        self.n_sdof = len(nm.unique(seq))
        self.n_new_dof = 0
Example #3
0
    def __init__(self, name, regions, dof_names, dof_map_fun, shift_fun,
                 variables, ts, functions):
        LCBCOperator.__init__(self, name, regions, dof_names, dof_map_fun,
                              variables, functions=functions)

        self.shift_fun = get_condition_value(shift_fun, functions,
                                             'LCBC', 'shift')

        mvar = variables[self.var_names[0]]
        svar = variables[self.var_names[1]]

        mfield = mvar.field
        sfield = svar.field

        nmaster = mfield.get_dofs_in_region(regions[0], merge=True)
        nslave = sfield.get_dofs_in_region(regions[1], merge=True)

        if nmaster.shape != nslave.shape:
            msg = 'shifted EPBC node list lengths do not match!\n(%s,\n %s)' %\
                  (nmaster, nslave)
            raise ValueError(msg)

        mcoor = mfield.get_coor(nmaster)
        scoor = sfield.get_coor(nslave)

        i1, i2 = self.dof_map_fun(mcoor, scoor)
        self.mdofs = expand_nodes_to_equations(nmaster[i1], dof_names[0],
                                               self.all_dof_names[0])
        self.sdofs = expand_nodes_to_equations(nslave[i2], dof_names[1],
                                               self.all_dof_names[1])

        self.shift = self.shift_fun(ts, scoor[i2], regions[1])

        meq = mvar.eq_map.eq[self.mdofs]
        seq = svar.eq_map.eq[self.sdofs]

        # Ignore DOFs with EBCs or EPBCs.
        mia = nm.where(meq >= 0)[0]
        sia = nm.where(seq >= 0)[0]

        ia = nm.intersect1d(mia, sia)

        meq = meq[ia]
        seq = seq[ia]

        num = len(ia)

        ones = nm.ones(num, dtype=nm.float64)
        n_dofs = [variables.adi.n_dof[ii] for ii in self.var_names]
        mtx = sp.coo_matrix((ones, (meq, seq)), shape=n_dofs)

        self.mtx = mtx.tocsr()

        self.rhs = self.shift.ravel()[ia]

        self.ameq = meq
        self.aseq = seq

        self.n_mdof = len(nm.unique(meq))
        self.n_sdof = len(nm.unique(seq))
        self.n_new_dof = 0
Example #4
0
    def __init__(self, name, regions, dof_names, dof_map_fun,
                 constraints, variables, ts=None, functions=None):
        MRLCBCOperator.__init__(self, name, regions, dof_names, dof_map_fun,
                                variables, functions=functions)
        import sympy as sm

        n_c = self.field.n_components
        dpn = len(self.dof_names)
        n_nod = self.mdofs.shape[0]

        assert_(dpn <= n_c)

        if (isinstance(constraints, basestr)
            or isinstance(constraints, Function)):
            fun = get_condition_value(constraints, functions,
                                      'nodal', 'constraints')
            coors = self.field.get_coor(self.mdofs)
            mtx, rhs = fun(ts, coors, self.region)

        else:
            mtx, rhs = constraints
            mtx = nm.tile(mtx, (n_nod, 1, 1))
            rhs = nm.tile(rhs, (n_nod, 1))

        n_ceq = mtx.shape[1]

        assert_(n_ceq == rhs.shape[1])
        assert_(dpn == mtx.shape[2])
        assert_(n_ceq <= dpn)

        data = []
        rows = []
        cols = []
        rhss = nm.zeros(n_nod * dpn, dtype=nm.float64)
        n_new = 0
        us = [sm.Symbol('u%d' % ii) for ii in range(dpn)]
        for im, nmtx in enumerate(mtx):
            eqs = sm.Matrix(nmtx) * sm.Matrix(us) - rhs[im][:, None]
            sol = sm.solve(eqs)

            assert_(len(sol) == n_ceq)

            imasters = []
            ifixed = []
            islaves = set()
            ccs = []
            for key, _poly in six.iteritems(sol):
                imaster = int(key.name[1:])
                imasters.append(imaster)

                if not isinstance(_poly, sm.Float):
                    poly = _poly.as_poly()

                    # Workaround for poly.all_coeffs() not applicable to
                    # multivariate polynomials.
                    coefs = []
                    for ii, uu in enumerate(us):
                        if poly.has(uu):
                            coefs.append(poly.coeff_monomial(uu))
                            islaves.add(ii)
                    coefs.append(poly.TC())
                    ccs.append(coefs)

                else: # Degenerated constraint - fixed master.
                    ifixed.append(imaster)
                    ccs.append([float(_poly)])

            islaves = sorted(islaves)

            for ii, imaster in enumerate(imasters):
                coefs = ccs[ii]

                em = dpn * im + imaster
                rhss[em] = coefs[-1]

                if imaster in ifixed: continue

                # Master DOF is expressed in terms of slave DOFs.
                for ii, islave in enumerate(islaves):
                    es = ii + n_new

                    rows.append(em)
                    cols.append(es)
                    data.append(coefs[ii])

            # Slave DOFs are copied.
            for ii, islave in enumerate(islaves):
                em = dpn * im + islave
                es = ii + n_new

                rows.append(em)
                cols.append(es)
                data.append(1.0)

            n_new += len(islaves)

        rows = nm.array(rows, dtype=nm.int32)
        cols = nm.array(cols, dtype=nm.int32)
        data = nm.array(data, dtype=nm.float64)

        mtx = sp.coo_matrix((data, (rows, cols)), shape=(n_nod * dpn, n_new))

        self.n_mdof = n_nod * dpn
        self.n_new_dof = n_new
        self.mtx = mtx.tocsr()

        self.rhs = rhss
Example #5
0
    def map_equations(self, bcs, field, ts, functions, problem=None,
                      warn=False):
        """
        Create the mapping of active DOFs from/to all DOFs.

        Parameters
        ----------
        bcs : Conditions instance
            The Dirichlet or periodic boundary conditions (single
            condition instances). The dof names in the conditions must
            already be canonized.
        field : Field instance
            The field of the variable holding the DOFs.
        ts : TimeStepper instance
            The time stepper.
        functions : Functions instance
            The registered functions.
        problem : Problem instance, optional
            The problem that can be passed to user functions as a context.
        warn : bool, optional
            If True, warn about BC on non-existent nodes.

        Returns
        -------
        active_bcs : set
            The set of boundary conditions active in the current time.

        Notes
        -----
        - Periodic bc: master and slave DOFs must belong to the same
          field (variables can differ, though).
        """
        if bcs is None:
            self._init_empty(field)
            return set()

        eq_ebc = nm.zeros((self.var_di.n_dof,), dtype=nm.int32)
        val_ebc = nm.zeros((self.var_di.n_dof,), dtype=field.dtype)
        master_slave = nm.zeros((self.var_di.n_dof,), dtype=nm.int32)
        chains = []

        active_bcs = set()
        for bc in bcs:
            # Skip conditions that are not active in the current time.
            if not is_active_bc(bc, ts=ts, functions=functions):
                continue

            active_bcs.add(bc.key)
            if isinstance(bc, DGEssentialBC):
                ntype = "DGEBC"
                region = bc.region
            elif isinstance(bc, DGPeriodicBC):
                ntype = "DGEPBC"
                region = bc.regions[0]
            elif isinstance(bc, EssentialBC):
                ntype = 'EBC'
                region = bc.region
            elif isinstance(bc, PeriodicBC):
                ntype = 'EPBC'
                region = bc.regions[0]

            if warn:
                clean_msg = ('warning: ignoring nonexistent %s node (%s) in '
                             % (ntype, self.var_di.var_name))
            else:
                clean_msg = None

            # Get master region nodes.
            master_nod_list = field.get_dofs_in_region(region)
            if len(master_nod_list) == 0:
                continue

            if ntype == 'EBC': # EBC.
                dofs, val = bc.dofs
                ##
                # Evaluate EBC values.
                fun = get_condition_value(val, functions, 'EBC', bc.name)
                if isinstance(fun, Function):
                    aux = fun
                    fun = lambda coors: aux(ts, coors,
                                            bc=bc, problem=problem)

                nods, vv = field.set_dofs(fun, region, len(dofs), clean_msg)

                eq = expand_nodes_to_equations(nods, dofs, self.dof_names)
                # Duplicates removed here...
                eq_ebc[eq] = 1
                if vv is not None: val_ebc[eq] = nm.ravel(vv)
            elif ntype == "DGEBC":

                dofs, val = bc.dofs
                ##
                # Evaluate EBC values.
                fun = get_condition_value(val, functions, 'EBC', bc.name)
                if isinstance(fun, Function):
                    aux = fun
                    fun = lambda coors: aux(ts, coors,
                                            bc=bc, problem=problem)

                values = field.get_bc_facet_values(fun, region, diff=bc.diff)
                bc2bfi = field.get_bc_facet_idx(region)

                self.dg_ebc_val.setdefault(bc.diff, []).append(values)
                self.dg_ebc.setdefault(bc.diff, []).append(bc2bfi)
                self.n_dg_ebc += 1
            elif ntype == "DGEPBC":

                # ensure matching boundaries?
                master_bc2bfi = field.get_bc_facet_idx(region)
                slave_bc2bfi = field.get_bc_facet_idx(bc.regions[1])

                self.dg_epbc.append((master_bc2bfi, slave_bc2bfi))
                self.n_dg_epbc += 1

            else: # EPBC.
                region = bc.regions[1]
                slave_nod_list = field.get_dofs_in_region(region)

                nmaster = nm.unique(master_nod_list)
                # Treat fields not covering the whole domain.
                if nmaster[0] == -1:
                    nmaster = nmaster[1:]

                nslave = nm.unique(slave_nod_list)
                # Treat fields not covering the whole domain.
                if nslave[0] == -1:
                    nslave = nslave[1:]

                ## print nmaster + 1
                ## print nslave + 1
                if nmaster.shape != nslave.shape:
                    msg = 'EPBC list lengths do not match!\n(%s,\n %s)' %\
                          (nmaster, nslave)
                    raise ValueError(msg)

                if (nmaster.shape[0] == 0) and (nslave.shape[0] == 0):
                    continue

                mcoor = field.get_coor(nmaster)
                scoor = field.get_coor(nslave)

                fun = get_condition_value(bc.match, functions, 'EPBC', bc.name)
                if isinstance(fun, Function):
                    i1, i2 = fun(mcoor, scoor)

                else:
                    i1, i2 = fun

                ## print nm.c_[mcoor[i1], scoor[i2]]
                ## print nm.c_[nmaster[i1], nslave[i2]] + 1

                meq = expand_nodes_to_equations(nmaster[i1], bc.dofs[0],
                                                self.dof_names)
                seq = expand_nodes_to_equations(nslave[i2], bc.dofs[1],
                                                self.dof_names)

                m_assigned = nm.where(master_slave[meq] != 0)[0]
                s_assigned = nm.where(master_slave[seq] != 0)[0]
                if m_assigned.size or s_assigned.size: # Chain EPBC.
                    aux = master_slave[meq[m_assigned]]
                    sgn = nm.sign(aux)
                    om_chain = zip(meq[m_assigned], (aux - sgn) * sgn)
                    chains.extend(om_chain)

                    aux = master_slave[seq[s_assigned]]
                    sgn = nm.sign(aux)
                    os_chain = zip(seq[s_assigned], (aux - sgn) * sgn)
                    chains.extend(os_chain)

                    m_chain = zip(meq[m_assigned], seq[m_assigned])
                    chains.extend(m_chain)

                    msd = nm.setdiff1d(s_assigned, m_assigned)
                    s_chain = zip(meq[msd], seq[msd])
                    chains.extend(s_chain)

                    msa = nm.union1d(m_assigned, s_assigned)
                    ii = nm.setdiff1d(nm.arange(meq.size), msa)
                    master_slave[meq[ii]] = seq[ii] + 1
                    master_slave[seq[ii]] = - meq[ii] - 1

                else:
                    master_slave[meq] = seq + 1
                    master_slave[seq] = - meq - 1

        chains = group_chains(chains)
        resolve_chains(master_slave, chains)

        self.master = nm.nonzero(master_slave > 0)[0]
        self.slave = master_slave[self.master] - 1

        # Propagate EBCs via PBCs.
        mask = eq_ebc[self.master] > 0
        im0 = self.master[mask]
        im1 = self.slave[mask]
        mask = eq_ebc[self.slave] > 0
        is0 = self.slave[mask]
        is1 = self.master[mask]
        val_ebc[im1] = val_ebc[im0]
        eq_ebc[im1] = eq_ebc[im0]
        val_ebc[is1] = val_ebc[is0]
        eq_ebc[is1] = eq_ebc[is0]

        self.eq_ebc = nm.nonzero(eq_ebc > 0)[0]
        self.val_ebc = val_ebc[self.eq_ebc]
        assert_((self.eq_ebc.shape == self.val_ebc.shape))

        self.eq[self.eq_ebc] = -2
        self.eq[self.master] = -1

        self._mark_unused(field)

        self.eqi = self.eq[self.eq >= 0]
        self.eq[self.eqi] = nm.arange(self.eqi.shape[0], dtype=nm.int32)
        self.eq[self.master] = self.eq[self.slave]
        self.n_eq = self.eqi.shape[0]
        self.n_ebc = self.eq_ebc.shape[0]
        self.n_epbc = self.master.shape[0]

        return active_bcs
Example #6
0
    def map_equations(self, bcs, field, ts, functions, problem=None,
                      warn=False):
        """
        Create the mapping of active DOFs from/to all DOFs.

        Parameters
        ----------
        bcs : Conditions instance
            The Dirichlet or periodic boundary conditions (single
            condition instances). The dof names in the conditions must
            already be canonized.
        field : Field instance
            The field of the variable holding the DOFs.
        ts : TimeStepper instance
            The time stepper.
        functions : Functions instance
            The registered functions.
        problem : Problem instance, optional
            The problem that can be passed to user functions as a context.
        warn : bool, optional
            If True, warn about BC on non-existent nodes.

        Returns
        -------
        active_bcs : set
            The set of boundary conditions active in the current time.

        Notes
        -----
        - Periodic bc: master and slave DOFs must belong to the same
          field (variables can differ, though).
        """
        if bcs is None:
            self._init_empty(field)
            return set()

        eq_ebc = nm.zeros((self.var_di.n_dof,), dtype=nm.int32)
        val_ebc = nm.zeros((self.var_di.n_dof,), dtype=field.dtype)
        master_slave = nm.zeros((self.var_di.n_dof,), dtype=nm.int32)
        chains = []

        active_bcs = set()
        for bc in bcs:
            # Skip conditions that are not active in the current time.
            if not is_active_bc(bc, ts=ts, functions=functions):
                continue

            active_bcs.add(bc.key)

            if isinstance(bc, EssentialBC):
                ntype = 'EBC'
                region = bc.region

            else:
                ntype = 'EPBC'
                region = bc.regions[0]

            if warn:
                clean_msg = ('warning: ignoring nonexistent %s node (%s) in '
                             % (ntype, self.var_di.var_name))
            else:
                clean_msg = None

            # Get master region nodes.
            master_nod_list = field.get_dofs_in_region(region)
            if len(master_nod_list) == 0:
                continue

            if ntype == 'EBC': # EBC.
                dofs, val = bc.dofs
                ##
                # Evaluate EBC values.
                fun = get_condition_value(val, functions, 'EBC', bc.name)
                if isinstance(fun, Function):
                    aux = fun
                    fun = lambda coors: aux(ts, coors,
                                            bc=bc, problem=problem)

                nods, vv = field.set_dofs(fun, region, len(dofs), clean_msg)

                eq = expand_nodes_to_equations(nods, dofs, self.dof_names)
                # Duplicates removed here...
                eq_ebc[eq] = 1
                if vv is not None: val_ebc[eq] = nm.ravel(vv)

            else: # EPBC.
                region = bc.regions[1]
                slave_nod_list = field.get_dofs_in_region(region)

                nmaster = nm.unique(nm.hstack(master_nod_list))
                # Treat fields not covering the whole domain.
                if nmaster[0] == -1:
                    nmaster = nmaster[1:]

                nslave = nm.unique(nm.hstack(slave_nod_list))
                # Treat fields not covering the whole domain.
                if nslave[0] == -1:
                    nslave = nslave[1:]

                ## print nmaster + 1
                ## print nslave + 1
                if nmaster.shape != nslave.shape:
                    msg = 'EPBC list lengths do not match!\n(%s,\n %s)' %\
                          (nmaster, nslave)
                    raise ValueError(msg)

                if (nmaster.shape[0] == 0) and (nslave.shape[0] == 0):
                    continue

                mcoor = field.get_coor(nmaster)
                scoor = field.get_coor(nslave)

                fun = get_condition_value(bc.match, functions, 'EPBC', bc.name)
                if isinstance(fun, Function):
                    i1, i2 = fun(mcoor, scoor)

                else:
                    i1, i2 = fun

                ## print nm.c_[mcoor[i1], scoor[i2]]
                ## print nm.c_[nmaster[i1], nslave[i2]] + 1

                meq = expand_nodes_to_equations(nmaster[i1], bc.dofs[0],
                                                self.dof_names)
                seq = expand_nodes_to_equations(nslave[i2], bc.dofs[1],
                                                self.dof_names)

                m_assigned = nm.where(master_slave[meq] != 0)[0]
                s_assigned = nm.where(master_slave[seq] != 0)[0]
                if m_assigned.size or s_assigned.size: # Chain EPBC.
                    aux = master_slave[meq[m_assigned]]
                    sgn = nm.sign(aux)
                    om_chain = zip(meq[m_assigned], (aux - sgn) * sgn)
                    chains.extend(om_chain)

                    aux = master_slave[seq[s_assigned]]
                    sgn = nm.sign(aux)
                    os_chain = zip(seq[s_assigned], (aux - sgn) * sgn)
                    chains.extend(os_chain)

                    m_chain = zip(meq[m_assigned], seq[m_assigned])
                    chains.extend(m_chain)

                    msd = nm.setdiff1d(s_assigned, m_assigned)
                    s_chain = zip(meq[msd], seq[msd])
                    chains.extend(s_chain)

                    msa = nm.union1d(m_assigned, s_assigned)
                    ii = nm.setdiff1d(nm.arange(meq.size), msa)
                    master_slave[meq[ii]] = seq[ii] + 1
                    master_slave[seq[ii]] = - meq[ii] - 1

                else:
                    master_slave[meq] = seq + 1
                    master_slave[seq] = - meq - 1

        chains = group_chains(chains)
        resolve_chains(master_slave, chains)

        ii = nm.argwhere(eq_ebc == 1)
        self.eq_ebc = nm.atleast_1d(ii.squeeze())
        self.val_ebc = nm.atleast_1d(val_ebc[ii].squeeze())
        self.master = nm.argwhere(master_slave > 0).squeeze()
        self.slave = master_slave[self.master] - 1

        assert_((self.eq_ebc.shape == self.val_ebc.shape))
        self.eq[self.eq_ebc] = -2
        self.eq[self.master] = -1

        self._mark_unused(field)

        self.eqi = nm.compress(self.eq >= 0, self.eq)
        self.eq[self.eqi] = nm.arange(self.eqi.shape[0], dtype=nm.int32)
        self.eq[self.master] = self.eq[self.slave]
        self.n_eq = self.eqi.shape[0]
        self.n_ebc = self.eq_ebc.shape[0]
        self.n_epbc = self.master.shape[0]

        return active_bcs