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)
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
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
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
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
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