def _priority(self, priority_order, facet_domains): if len(priority_order) == 0: ds = [Measure("ds")] bcs = [None] return ds, bcs ds = Measure("ds")[facet_domains] unprioritized = list( set(np.unique(facet_domains.array())) - set(priority_order)) unprioritized = gather(unprioritized, 0) unprioritized = np.unique(np.array(unprioritized)) unprioritized = broadcast(unprioritized, 0) unprioritized = unprioritized.astype(np.int) _ds = [] if len(unprioritized) > 0: nds = ds(unprioritized[0]) for i in unprioritized[1:]: nds += ds(i) _ds.append(nds) _ds += [ds(i) for i in priority_order] bcs = [ DirichletBC(V, Constant((0, ) * V.num_sub_spaces()), facet_domains, i) for i in priority_order ] if len(unprioritized) > 0: bcs = [None] + bcs return _ds, bcs
def compute(self, get): # Get field to probe u = get(self.valuename) # Evaluate in all points self.probes(u) # Fetch array with probe values at this timestep #results = self.probes.array(self._probetimestep) results = self.probes.array() if MPI.rank(mpi_comm_world()) != 0: results = np.array([], dtype=np.float_) if results.shape == (): results = results.reshape(1,) # Broadcast array to all processes if self.params.broadcast_results: results = broadcast(results, 0) self.probes.clear() # Return as list to store without 'array(...)' text. if u.value_rank() > 0: if len(results.shape) == 1: return list(results) return list(tuple(res) for res in results) elif results.size == 1: return float(results) else: return list(results)
def create_submesh(mesh, markers, marker): "This function allows for a SubMesh-equivalent to be created in parallel" # Build mesh submesh = Mesh() mesh_editor = MeshEditor() mesh_editor.open(submesh, mesh.ufl_cell().cellname(), mesh.ufl_cell().topological_dimension(), mesh.ufl_cell().geometric_dimension()) # Return empty mesh if no matching markers if MPI.sum(mpi_comm_world(), int(marker in markers.array())) == 0: cbc_warning( "Unable to find matching markers in meshfunction. Submesh is empty." ) mesh_editor.close() return submesh base_cell_indices = np.where(markers.array() == marker)[0] base_cells = mesh.cells()[base_cell_indices] base_vertex_indices = np.unique(base_cells.flatten()) base_global_vertex_indices = sorted( [mesh.topology().global_indices(0)[vi] for vi in base_vertex_indices]) gi = mesh.topology().global_indices(0) shared_local_indices = set(base_vertex_indices).intersection( set(mesh.topology().shared_entities(0).keys())) shared_global_indices = [gi[vi] for vi in shared_local_indices] unshared_global_indices = list( set(base_global_vertex_indices) - set(shared_global_indices)) unshared_vertices_dist = distribution(len(unshared_global_indices)) # Number unshared vertices on separate process idx = sum(unshared_vertices_dist[:MPI.rank(mpi_comm_world())]) base_to_sub_global_indices = {} for gi in unshared_global_indices: base_to_sub_global_indices[gi] = idx idx += 1 # Gather all shared process on process 0 and assign global index all_shared_global_indices = gather(shared_global_indices, on_process=0, flatten=True) all_shared_global_indices = np.unique(all_shared_global_indices) shared_base_to_sub_global_indices = {} idx = int( MPI.max(mpi_comm_world(), float(max(base_to_sub_global_indices.values() + [-1e16]))) + 1) if MPI.rank(mpi_comm_world()) == 0: for gi in all_shared_global_indices: shared_base_to_sub_global_indices[int(gi)] = idx idx += 1 # Broadcast global numbering of all shared vertices shared_base_to_sub_global_indices = dict( zip(broadcast(shared_base_to_sub_global_indices.keys(), 0), broadcast(shared_base_to_sub_global_indices.values(), 0))) # Join shared and unshared numbering in one dict base_to_sub_global_indices = dict( base_to_sub_global_indices.items() + shared_base_to_sub_global_indices.items()) # Create mapping of local indices base_to_sub_local_indices = dict( zip(base_vertex_indices, range(len(base_vertex_indices)))) # Define sub-cells sub_cells = [None] * len(base_cells) for i, c in enumerate(base_cells): sub_cells[i] = [base_to_sub_local_indices[j] for j in c] # Store vertices as sub_vertices[local_index] = (global_index, coordinates) sub_vertices = {} for base_local, sub_local in base_to_sub_local_indices.items(): sub_vertices[sub_local] = (base_to_sub_global_indices[ mesh.topology().global_indices(0)[base_local]], mesh.coordinates()[base_local]) ## Done with base mesh # Distribute meshdata on (if any) empty processes sub_cells, sub_vertices = distribute_meshdata(sub_cells, sub_vertices) global_cell_distribution = distribution(len(sub_cells)) #global_vertex_distribution = distribution(len(sub_vertices)) global_num_cells = MPI.sum(mpi_comm_world(), len(sub_cells)) global_num_vertices = sum(unshared_vertices_dist) + MPI.sum( mpi_comm_world(), len(all_shared_global_indices)) mesh_editor.init_vertices(len(sub_vertices)) #mesh_editor.init_cells(len(sub_cells)) mesh_editor.init_cells_global(len(sub_cells), global_num_cells) global_index_start = sum( global_cell_distribution[:MPI.rank(mesh.mpi_comm())]) for index, cell in enumerate(sub_cells): if LooseVersion(dolfin_version()) >= LooseVersion("1.6.0"): mesh_editor.add_cell(index, *cell) else: mesh_editor.add_cell(int(index), global_index_start + index, np.array(cell, dtype=np.uintp)) for local_index, (global_index, coordinates) in sub_vertices.items(): #print coordinates mesh_editor.add_vertex_global(int(local_index), int(global_index), coordinates) mesh_editor.close() submesh.topology().init(0, len(sub_vertices), global_num_vertices) submesh.topology().init(mesh.ufl_cell().topological_dimension(), len(sub_cells), global_num_cells) # FIXME: Set up shared entities # What damage does this do? submesh.topology().shared_entities(0)[0] = [] # The code below sets up shared vertices, but lacks shared facets. # It is considered incomplete, and therefore commented out ''' #submesh.topology().shared_entities(0)[0] = [] from dolfin import compile_extension_module cpp_code = """ void set_shared_entities(Mesh& mesh, std::size_t idx, const Array<std::size_t>& other_processes) { std::set<unsigned int> set_other_processes; for (std::size_t i=0; i<other_processes.size(); i++) { set_other_processes.insert(other_processes[i]); //std::cout << idx << " --> " << other_processes[i] << std::endl; } //std::cout << idx << " --> " << set_other_processes[0] << std::endl; mesh.topology().shared_entities(0)[idx] = set_other_processes; } """ set_shared_entities = compile_extension_module(cpp_code).set_shared_entities base_se = mesh.topology().shared_entities(0) se = submesh.topology().shared_entities(0) for li in shared_local_indices: arr = np.array(base_se[li], dtype=np.uintp) sub_li = base_to_sub_local_indices[li] set_shared_entities(submesh, base_to_sub_local_indices[li], arr) ''' return submesh
def duplicate_meshfunction(mf, new_mesh): "Duplicate meshfunction defined on a different mesh" # Rebuild meshfunction mesh = mf.mesh() dim = mf.dim() if isinstance(mf, MeshFunctionSizet): f = MeshFunction("size_t", new_mesh, dim) dtype = np.uintp elif isinstance(mf, MeshFunctionDouble): f = MeshFunction("double", new_mesh, dim) dtype = np.float_ elif isinstance(mf, MeshFunctionBool): f = MeshFunction("bool", new_mesh, dim) dtype = np.bool elif isinstance(mf, MeshFunctionInt): f = MeshFunction("int", new_mesh, dim) dtype = np.int # Midpoint of old mesh connectivity = mesh.topology()(dim, 0)().reshape(mesh.num_entities(dim), -1) midpoints = np.mean(mesh.coordinates()[connectivity], axis=1) indices = np.lexsort(midpoints.T[::-1]) sorted_midpoints = midpoints[indices] values = mf.array()[indices] gdim = midpoints.shape[1] sorted_midpoints = sorted_midpoints.flatten() sorted_midpoints = gather(sorted_midpoints, 0) sorted_midpoints = np.hstack(sorted_midpoints).flatten() sorted_midpoints = broadcast(sorted_midpoints, 0) _sorted_midpoints = [] i = 0 for arr in sorted_midpoints: _sorted_midpoints.append(arr) sorted_midpoints = np.reshape(sorted_midpoints, newshape=(-1, gdim)) values = gather(values, 0) values = np.hstack(values).flatten() values = broadcast(values, 0) # Workaround for bug in np.uint64 if dtype == np.uintp: M = max(values) if M == dtype(-1): values[values == M] = -1 values = values.astype(dtype) _values = [] for arr in values: _values.append(arr) values = np.array(_values, dtype=dtype) indices = np.lexsort(sorted_midpoints.T[::-1]) values = values[indices] sorted_midpoints = sorted_midpoints[indices] # Now has full list of midpoint+values on all processes # Sort midpoints on new mesh on current process connectivity = new_mesh.topology()(dim, 0)().reshape(new_mesh.num_entities(dim), -1) midpoints = np.mean(new_mesh.coordinates()[connectivity], axis=1) indices = np.lexsort(midpoints.T[::-1]) midpoints = midpoints[indices] idx = 0 omp = sorted_midpoints[idx] tol = 1e-8 for i, mp in enumerate(midpoints): for j in xrange(gdim): while omp[j] < mp[j] - tol: idx += 1 omp[:] = sorted_midpoints[idx] f[int(indices[i])] = values[idx] return f
def compute_connectivity(mesh, cell_connectivity=True): """Compute connected regions of mesh. Regions are considered connected if they share a vertex through an edge. """ # Compute first vertex connectivity (defined by sharing edges) mesh.init(0,1) regions = VertexFunction("size_t", mesh) regions.set_all(0) i = 0 while True: i += 1 unset = np.where(regions.array()==0)[0] if len(unset) == 0: break start = unset[0] tic() connectivity = _compute_connected_vertices(mesh, start) regions.array()[connectivity.array()] = i dist = distribution(np.max(regions.array())) # Make all regions separate (regions on different processes are currently considered disjoint) regions.array()[:] += np.sum(dist[:MPI.rank(mesh.mpi_comm())]) # Find global indices of all vertices shared by more than one process global_indices = mesh.topology().global_indices(0) se = mesh.topology().shared_entities(0) gi_local = np.array([global_indices[i] for i in se.keys()]) #mapping = dict(zip(gi_local,se.keys())) gi = gather(gi_local, 0) gi = np.hstack(gi).flatten() gi = broadcast(gi, 0) # gi is now common on all processes # Connect disjointed regions through shared vertices while True: v = regions.array()[se.keys()] d = dict(zip(gi_local,v)) shift = dict() for gidx in gi: #lidx = mapping.get(gidx, -1) this_v = d.get(gidx, np.inf) v = int(MPI.min(mesh.mpi_comm(), float(this_v))) if this_v == v or this_v == np.inf: continue shift[this_v] = v # Check if no shift is needed, and if so, break no_shift = bool(int(MPI.min(mesh.mpi_comm(), float(int(shift==dict()))))) if no_shift: break for k,v in shift.items(): regions.array()[regions.array()==k] = v # Condense regions, so that M == number of regions M = int(MPI.max(mesh.mpi_comm(), float(np.max(regions.array())))) values = np.unique(regions.array()) for i in range(1,M+1): has_value = MPI.max(mesh.mpi_comm(), float(i in values)) if has_value == 0: regions.array()[regions.array()>i] -= 1 values = np.unique(regions.array()) if cell_connectivity: cf = CellFunction("size_t", mesh) cf.set_all(0) cells = mesh.cells()[:,0] cf.array()[:] = regions.array()[cells] regions = cf return regions
def restriction_map(V, Vb, _all_coords=None, _all_coordsb=None): "Return a map between dofs in Vb to dofs in V. Vb's mesh should be a submesh of V's Mesh." if V.ufl_element().family( ) == "Discontinuous Lagrange" and V.ufl_element().degree() > 0: raise RuntimeError( "This function does not work for DG-spaces of degree >0 \ (several dofs associated with same point in same subspace)." ) if V.ufl_element().family() != "Lagrange": cbc_warning("This function is only tested for CG-spaces.") assert V.ufl_element().family() == Vb.ufl_element().family( ), "ufl elements differ in the two spaces" assert V.ufl_element().degree() == Vb.ufl_element().degree( ), "ufl elements differ in the two spaces" assert V.ufl_element().cell() == Vb.ufl_element().cell( ), "ufl elements differ in the two spaces" D = V.mesh().geometry().dim() # Recursively call this function if V has sub-spaces if V.num_sub_spaces() > 0: mapping = {} if MPI.size(mpi_comm_world()) == 1: if _all_coords is None: try: # For 1.6.0+ and newer all_coords = V.tabulate_dof_coordinates().reshape( V.dim(), D) all_coordsb = Vb.tabulate_dof_coordinates().reshape( Vb.dim(), D) except: # For 1.6.0 and older all_coords = V.dofmap().tabulate_all_coordinates( V.mesh()).reshape(V.dim(), D) all_coordsb = Vb.dofmap().tabulate_all_coordinates( Vb.mesh()).reshape(Vb.dim(), D) else: all_coords = _all_coords all_coordsb = _all_coordsb else: all_coords = None all_coordsb = None for i in range(V.num_sub_spaces()): mapping.update( restriction_map(V.sub(i), Vb.sub(i), all_coords, all_coordsb)) return mapping dm = V.dofmap() dmb = Vb.dofmap() N = len(dm.dofs()) Nb = len(dmb.dofs()) dofs = dm.dofs() # Extract coordinates of dofs if dm.is_view(): if _all_coords is not None: coords = _all_coords[V.dofmap().dofs()] else: try: # For 1.6.0+ and newer coords = V.collapse().tabulate_dof_coordinates().reshape(N, D) except: # For 1.6.0 and older coords = V.collapse().dofmap().tabulate_all_coordinates( V.mesh()).reshape(N, D) if _all_coordsb is not None: coordsb = _all_coordsb[Vb.dofmap().dofs()] else: try: # For 1.6.0+ and newer coordsb = Vb.collapse().tabulate_dof_coordinates().reshape( Nb, D) except: # For 1.6.0 and older coordsb = Vb.collapse().dofmap().tabulate_all_coordinates( Vb.mesh()).reshape(Nb, D) else: if LooseVersion(dolfin_version()) > LooseVersion("1.6.0"): # For 1.6.0+ and newer coords = V.tabulate_dof_coordinates().reshape(N, D) coordsb = Vb.tabulate_dof_coordinates().reshape(Nb, D) else: # For 1.6.0 and older coords = V.dofmap().tabulate_all_coordinates(V.mesh()).reshape( N, D) coordsb = Vb.dofmap().tabulate_all_coordinates(Vb.mesh()).reshape( Nb, D) # Build KDTree to compute distances from coordinates in base kdtree = KDTree(coords) eps = 1e-12 mapping = {} request_dofs = np.array([]) distances, indices = kdtree.query(coordsb) for i, subdof in enumerate(dmb.dofs()): # Find closest dof in base #d, idx = kdtree.query(coordsb[i]) d, idx = distances[i], indices[i] if d < eps: # Dof found on this process, add to map dof = dofs[idx] assert subdof not in mapping mapping[subdof] = dof else: # Search for this dof on other processes add_dofs = np.hstack(([subdof], coordsb[i])) request_dofs = np.append(request_dofs, add_dofs) del distances del indices # Scatter all dofs not found on current process to all processes all_request_dofs = [None] * MPI.size(mpi_comm_world()) for j in xrange(MPI.size(mpi_comm_world())): all_request_dofs[j] = broadcast(request_dofs, j) # Re-order all requested dofs # Remove items coming from this process all_request_dofs[MPI.rank(mpi_comm_world())] = [] all_request_dofs = np.hstack(all_request_dofs) all_request_dofs = all_request_dofs.reshape( len(all_request_dofs) / (D + 1), D + 1) all_request_dofs = dict( zip(all_request_dofs[:, 0], all_request_dofs[:, 1:])) # Search this process for all dofs not found on same process as subdof for subdof, coordsbi in all_request_dofs.items(): subdof = int(subdof) # Find closest dof in base d, idx = kdtree.query(coordsbi) if d < eps: # Dof found on this process, add to map dof = dofs[idx] assert subdof not in mapping mapping[subdof] = dof return mapping
def solve(self, problem, timer): assert isinstance(problem, FSIProblem) mesh = problem.mesh bmesh = BoundaryMesh(mesh, "exterior") dim = mesh.geometry().dim() dx = problem.dx ds = problem.ds n = FacetNormal(mesh) dt, timesteps, start_timestep = compute_regular_timesteps(problem) dt = Constant(dt) t = Constant(timesteps[start_timestep], name="TIME") # Function spaces spaces = NSSpacePoolSplit(mesh, self.params.u_degree, self.params.p_degree) V = spaces.V Q = spaces.Q D = spaces.spacepool.get_custom_space("CG", 1, (dim, )) Db = spaces.spacepool.get_custom_space("CG", 1, (dim, ), boundary=True) Dgb = spaces.spacepool.get_custom_space("CG", 1, (dim, ), boundary=True) # Trial- and testfunctions u, v = TrialFunction(V), TestFunction(V) # Velocity p, q = TrialFunction(Q), TestFunction(Q) # Pressure eta, x = TrialFunction(Dgb), TestFunction(Dgb) # Boundary displacement d, e = TrialFunction(D), TestFunction(D) # Mesh displacement # Solution functions U = Function(V) # Velocity P = Function(Q) # Pressure DF = Function(D) # Fluid (full mesh) displacement # Helper functions U1 = Function(V) U2 = Function(V) DF1 = Function(D) DF2 = Function(D) ETA1 = Function(Dgb) # eta time derivatives Uext = Extrapolation(V, self.params.r) # Velocity extrapolation Pext = Extrapolation(Q, self.params.s) # Pressure extrapolation phi = p - Pext phiext = Extrapolation(Q, self.params.r) DFext = Extrapolation(D, self.params.s) DFext1, DFext2 = Function(D), Function(D) w = Function(D) db = Function(Db) dgb = Function(Dgb) dgb1, dgb2 = Function(Dgb), Function(Dgb) traction = Function(Dgb) # Get functions for data assimilation observations = problem.observations(spaces, t) controls = problem.controls(spaces) # Make scheme-specific representation of bcs bcs = problem.boundary_conditions(spaces, U, P, t, None) bcu = make_velocity_bcs(problem, spaces, bcs) bcp = make_pressure_bcs(problem, spaces, bcs) bcs_eta = [DirichletBC(D, DF, DomainBoundary()) ] # Are these for eta or full (fluid) mesh displacement? bcs_eta += [ DirichletBC(D, expr, problem.facet_domains, i) for expr, i in bcs[2] ] # Dgb defined in bdry_mesh, facet domains on mesh # Create a facet dgb_mesh = Dgb.mesh() dgb_dim = dgb_mesh.topology().dim() eta_boundaries = MeshFunction('size_t', dgb_mesh, dgb_dim - 1) eta_boundaries.set_all(0) Left().mark(eta_boundaries, 1) Right().mark(eta_boundaries, 2) #plot(eta_boundaries, interactive=True) #embed() #sys.exit() #bcs_shell = [DirichletBC(Dgb, expr, DomainBoundary(), method="pointwise") for expr, i in bcs[2]] # really for eta #shellbc1 = DirichletBC(Dgb, Constant((0, 0)), eta_boundaries, 1, method="pointwise") #shellbc2 = DirichletBC(Dgb, Constant((0, 0)), eta_boundaries, 2, method="pointwise") shellbc1 = DirichletBC(Dgb, Constant((0, 0)), eta_boundaries, 1) shellbc2 = DirichletBC(Dgb, Constant((0, 0)), eta_boundaries, 2) bcs_shell = [shellbc1, shellbc2] #embed() #sys.exit() # Create boundary integrals over structure and non-structure part of mesh # nds = non-fixed part of boundary # fds = fixed part of boundary (has bcs for displacement) fixed_boundaries = [i for _, i in bcs[2]] # bc2 is bceta nonfixed_boundaries = list( set(np.unique(problem.facet_domains.array())) - set(fixed_boundaries)) nonfixed_boundaries = gather(nonfixed_boundaries, 0) nonfixed_boundaries = np.unique(np.array(nonfixed_boundaries)) nonfixed_boundaries = broadcast(nonfixed_boundaries, 0) nonfixed_boundaries = nonfixed_boundaries.astype(np.int) assert len(nonfixed_boundaries) > 0 nds = ds(nonfixed_boundaries[0]) # Is nds Sigma? for i in nonfixed_boundaries[1:]: nds += ds(i) if len(fixed_boundaries) > 0: fds = ds(fixed_boundaries[0]) # Is fds Gamma? for i in fixed_boundaries[1:]: fds += ds(i) def par(f, n): "Return parallel/tangential component of f" return f - dot(f, n) * n mu = Constant(problem.params.mu) # Fluid viscosity rho_f = Constant(problem.params.rho) # Fluid density rho_s = Constant(problem.params.rho_s) # Structure density h_s = Constant(problem.params.h) # Thickness if isinstance(problem.params.R, float): R = Constant(problem.params.R) else: R = problem.params.R beta = Constant(problem.params.E * float(h_s) / (1 - problem.params.nu**2) * 1.0 / R**2) beta1 = Constant(0.5 * problem.params.E * float(h_s) / (1 + problem.params.nu)) alpha = Constant(1) alpha1 = Constant(1e-3) # Set up Field (see cbcpost documentation) to compute boundary traction T_bdry = BoundaryTraction() T_bdry.before_first_compute(lambda x: U) r = self.params.r s = self.params.s I = SpatialCoordinate(mesh) A = I + DF # ALE map F = grad(A) J = det(F) # Tentative velocity, Eq. 30, mapped to reference mesh # Eq. 30.1 a1 = inner(rho_f * (u - U1) / dt, v) * J * dx() # Is this mapping correct? #a1 = inner(rho_f*(u-U1)/dt, v)*dx() # Is this mapping correct? a1 += rho_f * inner((grad(u) * inv(F)) * (U1 - w), v) * J * dx() #a1 += rho_f*inner(grad(u)*U1, v)*dx() a1 += inner(J * Sigma(mu, u, Pext, F) * inv(F).T, grad(v)) * dx() #a1 += inner(sigma(mu, u, Pext), grad(v))*dx() a1 -= inner(J * Sigma(mu, u, Pext, F) * inv(F).T * n, v) * ds() #a1 -= inner(sigma(mu, u, Pext)*n, v)*ds() a1 += rho_f * inner( (grad(u) * inv(F)) * (U1 - w), v) * J * dx() # dot or * a1 += inner(J * Sigma(mu, u, Pext, F) * inv(F).T, grad(v)) * dx() # Eq. 30.2 #a1 += inner(sigma(mu, u, Pext)*n, v)*fds # Inflow/outflow. Should be Sigma? a1 += inner(Sigma(mu, u, Pext, F) * n, v) * fds # Matters only if Gamma is non-fixed? #a1 += inner(sigma(mu, u, Pext)*n, v)*fds # Matters only if Gamma is non-fixed? # Eq. 30.3 #a1 += inner(J*sigma(mu, u, Pext)*inv(F).T*n, v)*nds # Should be Sigma? a1 += inner(J * Sigma(mu, u, Pext, F) * inv(F).T * n, v) * nds # Sigma because boundary moves? a1 += inner(sigma(mu, u, Pext) * n, v) * nds # Sigma because boundary moves? a1 += rho_s * h_s / dt * inner(u, v) * nds # Should contain J? a1 -= rho_s * h_s / dt * inner( (DF1 - DF2) / dt + par(dt * (DFext - 2 * DFext1 + DFext2) / dt**2, n), v) * nds # Extrapolation cases of RHS of Eq. 30.3 if r == 1: _F = grad(I + DF1) _J = det(_F) #a1 -= 2*mu*inner(par(_J*Epsilon(U1, _F)*inv(_F).T*n, n), v)*nds a1 -= 2 * mu * inner(par(epsilon(U1) * n, n), v) * nds elif r == 2: _F = grad(I + DF1) _J = det(_F) a1 -= 2 * 2 * mu * inner( par(_J * Epsilon(U1, _F) * inv(_F).T * n, n), v) * nds _F = grad(I + DF2) _J = det(_F) a1 += 2 * mu * inner(par(_J * Epsilon(U2, _F) * inv(_F).T * n, n), v) * nds L1 = rhs(a1) a1 = lhs(a1) A1 = assemble(a1) b1 = assemble(L1) solver_u_tent = create_solver("gmres", "additive_schwarz") # Pressure, Eq 31, mapped to reference mesh (note phi=p - Pext) # Eq. 31.1 #a2 = inner(J*inv(F)*inv(F).T*grad(phi), grad(q))*dx() a2 = inner(dt / rho_f * J * inv(F) * inv(F).T * grad(phi), grad(q)) * dx() #a2 = inner(dt/rho_f*grad(phi), grad(q))*dx() #a2 -= inner(J*inv(F)*inv(F).T*grad(phi), q*n)*ds() a2 -= inner(dt / rho_f * J * inv(F) * inv(F).T * grad(phi), q * n) * ds() #a2 -= inner(dt/rho_f*grad(phi), q*n)*ds() a2 += div(J * inv(F) * U) * dx() #a2 += div(U)*dx() # Eq. 31.2 a2 += phi * q * fds a2 -= (P - Pext) * q * fds # Eq. 31.3 # Why no J? #a2 += dt/rho_f*dot(dot(grad(phi), n), q)*nds #a2 += dt/(rho_s*h_s)*phi*q*nds #a2 -= dt/(rho_s*h_s)*phiext*q*nds #a2 -= inner(Uext - (DFext - DFext1)/dt, n)*q*nds a2 += dt / rho_f * J * dot(dot(inv(F).T * grad(phi), inv(F).T * n), q) * nds a2 += dt / (rho_s * h_s) * J * phi * q * nds a2 -= dt / (rho_s * h_s) * J * phiext * q * nds a2 -= J * inner(Uext - (DFext - DFext1) / dt, inv(F).T * n) * q * nds # J*grad(phi)*inf(F), grad(q)*inf(F) a2 = inner(J * inv(F) * inv(F).T * grad(phi), grad(q)) * dx() # symmetry and * a2 -= inner(J * inv(F) * inv(F).T * grad(phi), q * n) * ds() # remove? a2 += div(J * inv(F) * U) * dx() #a2 += div(J*U*inv(F).T)*dx() # Eq. 31.2 a2 += phi * q * fds # jacobian missing? a2 -= (P - Pext) * q * fds # p_{gamma}(t_n) - Pext # Eq. 31.3 a2 += dt / rho_f * dot(dot(grad(phi), n), q) * nds # Are Fs and stuff missing? a2 += dt / (rho_s * h_s) * phi * q * nds a2 -= dt / (rho_s * h_s) * phiext * q * nds a2 -= inner(Uext - (DFext - DFext1) / dt, n) * q * nds L2 = rhs(a2) a2 = lhs(a2) A2 = assemble(a2, keep_diagonal=True) b2 = assemble(L2) solver_p_corr = create_solver("bicgstab", "amg") #solver_p_corr = LinearSolver() # Velocity correction (u^n = tilde(u)^n+tau/rho*grad phi^n) a3 = inner(v, u) * dx() a3 -= inner(v, U) * dx() a3 += dt / rho_f * inner(v, grad(P - Pext)) * dx() a3 += dt / rho_f * inner(v, grad(P - Pext)) * dx() # missing F? L3 = rhs(a3) a3 = lhs(a3) A3 = assemble(a3) b3 = assemble(L3) solver_u_corr = create_solver("gmres", "additive_schwarz") # Solid on boundary mesh (currently very simple model) # Is this solid sub-step eq. 1 p. 18? _dx = Measure("dx") a4 = rho_s * h_s / dt**2 * inner( eta - 2 * dgb1 + dgb2, x) * _dx # Second time-derivative of boundary displacement # Elastic operator a4 += inner(beta * eta, x) * _dx a4 += inner(beta1 * grad(eta), grad(x)) * _dx # -lambda1*dxx(eta) # Viscous operator a4 += inner(alpha * rho_s * h_s * (eta - ETA1) / dt, x) * _dx a4 += inner(alpha1 * beta1 * grad((eta - ETA1) / dt), grad(x)) * _dx a4 = rho_s * h_s / dt**2 * inner( eta - 2 * dgb1 + dgb2, x) * _dx # Second time-derivative of boundary displacement a4 += inner(beta * eta, x) * _dx #a4 += inner(PI(eta),x)*_dx a4 += inner(traction, x) * _dx # Force term L4 = rhs(a4) a4 = lhs(a4) A4 = assemble(a4) b4 = assemble(L4) solver_solid = create_solver("gmres", "hypre_euclid") # Mesh displacement (solve poisson equation with boundary displacement as bcs) a5 = inner(grad(d), grad(e)) * dx() L5 = inner(Constant((0, ) * dim), e) * dx() A5 = assemble(a5) b5 = assemble(L5) solver_displacement = create_solver( "gmres", "hypre_euclid") # same as solid solver. Seems to work #solver_displacement = create_solver("cg", "ml_amg") # fails to return a valid solver. # Helper functionality for getting boundary displacement as boundary condition local_dofmapping = boundarymesh_to_mesh_dofmap(bmesh, Db, D) _keys, _values = zip(*local_dofmapping.iteritems()) _keys = np.array(_keys, dtype=np.intc) _values = np.array(_values, dtype=np.intc) ofile = open("jconst.txt", "w") for timestep in xrange(start_timestep + 1, len(timesteps)): t.assign(timesteps[timestep]) # Update various functions problem.update(spaces, U, P, t, timestep, bcs, None, None) timer.completed("problem update") # Solve tentative velocity assemble(a1, tensor=A1) assemble(L1, tensor=b1) for bc in bcu: bc.apply(A1, b1) #solve(A1, U.vector(), b1) solver_u_tent.solve(A1, U.vector(), b1) # Solve pressure correction #assemble(a2, tensor=A2, keep_diagonal=True) b2.apply('insert') assemble(a2, tensor=A2) assemble(L2, tensor=b2) for bc in bcp: bc.apply(A2, b2) #solve(A2, P.vector(), b2) b2.apply("insert") solver_p_corr.solve(A2, P.vector(), b2) #P-vector().zero() #P.vector().axpy(1.0, phi.vector()) #P.vector().axpy(1.0, Pext.vector()) # Solve updated velocity assemble(a3, tensor=A3) assemble(L3, tensor=b3) for bc in bcu: bc.apply(A3, b3) #solve(A3, U.vector(), b3) solver_u_corr.solve(A3, U.vector(), b3) # Solve solid traction.assign( T_bdry.compute( lambda x: { "Velocity": U, "Pressure": P, "DynamicViscosity": mu, "Displacement": DF }[x])) assemble(a4, tensor=A4) assemble(L4, tensor=b4) # missing BC for eta?, i.e. a4 or is it don ethrough b4? #for bc in bcs_shell: # bc.apply(A4, b4) #embed() #sys.exit() #b4.array()[np.array([0, -1])] = 0 #solve(A4, dgb.vector(), b4) solver_solid.solve(A4, dgb.vector(), b4) # Solve mesh displacement db.interpolate(dgb) # Interpolate to vertices on boundary get_set_vector(DF.vector(), _keys, db.vector(), _values) # Set boundary values to function for bc in bcs_eta: bc.apply(A5, b5) solver_displacement.solve(A5, DF.vector(), b5) # Rotate functions U1.assign(U) DF2.assign(DF1) DF1.assign(DF) dgb2.assign(dgb1) dgb1.assign(dgb) w.assign(DF - DF1) w.vector()[:] *= 1. / float(dt) # Mesh velocity ETA1.assign(dgb) # FIXME: Not sure about this # Update extrapolations Uext.update(U) phiext.update(P - Pext) Pext.update(P) DFext2.assign(DFext1) DFext1.assign(DFext) DFext.update(DF) ofile.write("%s\n" % assemble(J * dx)) yield ParamDict(spaces=spaces, observations=None, controls=None, t=float(t), timestep=timestep, u=U, p=P, d=DF, state=(U, P, DF))