def test_Poisson_t3(self): from context import spyfe from spyfe.meshing.generators.triangles import t3_ablock from spyfe.meshing.modification import mesh_boundary from spyfe.meshing.selection import connected_nodes from numpy import array from spyfe.materials.mat_heatdiff import MatHeatDiff from spyfe.femms.femm_heatdiff import FEMMHeatDiff from spyfe.fields.nodal_field import NodalField from spyfe.integ_rules import TriRule from spyfe.force_intensity import ForceIntensity from scipy.sparse.linalg import spsolve import time from spyfe.meshing.exporters.vtkexporter import vtkexport start0 = time.time() # These are the constants in the problem, k is kappa boundaryf = lambda x, y: 1.0 + x**2 + 2 * y**2 Q = -6 # internal heat generation rate k = 1.0 # thermal conductivity m = MatHeatDiff(thermal_conductivity=array([[k, 0.0], [0.0, k]])) Dz = 1.0 # thickness of the slice start = time.time() N = 5 Length, Width, nL, nW = 1.0, 1.0, N, N fens, fes = t3_ablock(Length, Width, nL, nW) print('Mesh generation', time.time() - start) bfes = mesh_boundary(fes) cn = connected_nodes(bfes) geom = NodalField(fens=fens) temp = NodalField(nfens=fens.count(), dim=1) for index in cn: temp.set_ebc([index], val=boundaryf(fens.xyz[index, 0], fens.xyz[index, 1])) temp.apply_ebc() temp.numberdofs() femm = FEMMHeatDiff(material=m, fes=fes, integration_rule=TriRule(npts=1)) start = time.time() fi = ForceIntensity(magn=lambda x, J: Q) F = femm.distrib_loads(geom, temp, fi, 3) print('Heat generation load', time.time() - start) start = time.time() F += femm.nz_ebc_loads_conductivity(geom, temp) print('NZ EBC load', time.time() - start) start = time.time() K = femm.conductivity(geom, temp) print('Matrix assembly', time.time() - start) start = time.time() temp.scatter_sysvec(spsolve(K, F)) print('Solution', time.time() - start) print(temp.values) print('Done', time.time() - start0) from numpy.testing import assert_array_almost_equal assert_array_almost_equal(temp.values[-4:-1], array([[3.16], [3.36], [3.64]]))
maxiter=150 lamb, v, converged = spyfe.bipwr.gepbinvpwr2(K,M,v,tol,maxiter) if converged: ix = numpy.argsort(numpy.abs(lamb)) lamb = lamb[ix].real v = v[:, ix] print([math.sqrt(om) / 2.0 / math.pi for om in lamb]) print("Reference frequencies:") print([0.421, 1.029, 2.582, 3.306, 3.753, 6.555]) print('Solution', time.time() - start) else: print( 'Not converged!' ) # start = time.time() # w, v = eigsh(K, k=10, M=M, which='SM') # ix = numpy.argsort(numpy.abs(w)) # w = w[ix].real # v = v[:,ix] # print('EP solution', time.time() - start) # print([math.sqrt(om)/2.0/math.pi for om in w]) # print(w, v[:,0]) u.scatter_sysvec(v[:,0].real) # print('Done', time.time() - start0) # vtkexport("FV16_cantilevered_plate_abaqus_results", fes, geom, {"displacements": u})
temp.apply_ebc() femm = FEMMHeatDiff(material=m, fes=fes, integration_rule=GaussRule(dim=3, order=3)) S = femm.connection_matrix(geom) perm = reverse_cuthill_mckee(S, symmetric_mode=True) temp.numberdofs(node_perm=perm) # temp.numberdofs() start = time.time() fi = ForceIntensity(magn=lambda x, J: Q) F = femm.distrib_loads(geom, temp, fi, 3) print('Heat generation load', time.time() - start) start = time.time() F += femm.nz_ebc_loads_conductivity(geom, temp) print('NZ EBC load', time.time() - start) start = time.time() K = femm.conductivity(geom, temp) print('Matrix assembly', time.time() - start) start = time.time() # lu = splu(K) # T = lu.solve(F) # T = spsolve(K, F, use_umfpack=True) T, info = minres(K, F) print(info) temp.scatter_sysvec(T) print('Solution', time.time() - start) print('Done', time.time() - start0) vtkexport("Poisson_fe_H20_results", fes, geom, {"temp": temp})
for index in cn: temp.set_ebc([index], val=boundaryf(fens.xyz[index, 0], fens.xyz[index, 1])) temp.apply_ebc() femm = FEMMHeatDiff(material=m, fes=fes, integration_rule=GaussRule(dim=2, order=3)) # S = femm.connection_matrix(geom) # perm = reverse_cuthill_mckee(S,symmetric_mode=True) # temp.numberdofs(node_perm=perm) temp.numberdofs() start = time.time() fi = ForceIntensity(magn=lambda x, J: Q) F = femm.distrib_loads(geom, temp, fi, 3) print('Heat generation load', time.time() - start) start = time.time() F += femm.nz_ebc_loads_conductivity(geom, temp) print('NZ EBC load', time.time() - start) start = time.time() K = femm.conductivity(geom, temp) print('Matrix assembly', time.time() - start) start = time.time() temp.scatter_sysvec(spsolve(K, F)) print('Solution', time.time() - start) print('Done', time.time() - start0) # print(temp.values.T) vtkexport("Poisson_fe_Q8_results", fes, geom, {"temp": temp})
start = time.time() dT = NodalField(nfens=fens.count(), dim=1) dT.fun_set_values(fens.xyz, lambda x: math.sqrt(x[0]**2 + x[1]**2) + x[2]) print(numpy.max(dT.values)) print(numpy.min(dT.values)) F = femm.thermal_strain_loads(geom, u, dT) print('Load vector assembly', time.time() - start) print(numpy.max(F), numpy.min(F)) start = time.time() # U, info = lgmres(K, F) # print(info) lu = splu(K) del K U = lu.solve(F) u.scatter_sysvec(U) print('Solution', time.time() - start) # print('Done', time.time() - start0) stresses = femm.nodal_field_from_integr_points_spr( geom, u, u, dtempn1=dT, output=OUTPUT_CAUCHY, component=[0, 1, 2, 3, 4, 5]) pointA = fenode_select( fens, box=[707.107E-03, 707.107E-03, -707.107E-03, -707.107E-03, 0., 0.], inflate=htol) print(pointA) sigzzA = stresses.values[pointA, 2] print('Stress sigz @ A=', sigzzA / 1.e6, ', ', (sigzzA / sigma_z_A_ref * 100), ' %')
def statics(model_data): """Algorithm for static linear deformation (stress) analysis. :param model_data: Model data dictionary. model_data['fens'] = finite element node set (mandatory) For each region (connected piece of the domain made of a particular material), mandatory: model_data['regions']= list of dictionaries, one for each region Each region: region['femm'] = finite element set that covers the region (mandatory) For essential boundary conditions (optional): model_data['boundary_conditions']['essential']=list of dictionaries, one for each application of an essential boundary condition. For each EBC dictionary ebc: ebc['node_list'] = node list, ebc['comp'] = displacement component (zero-based), ebc['value'] = function to supply the prescribed value, default is lambda x: 0.0 :return: Success? True or false. The model_data object is modified. model_data['geom'] =the nodal field that is the geometry model_data['temp'] =the nodal field that is the computed temperature model_data['timings'] = timing of the individual operations """ # To be done # For essential boundary conditions (optional): # cell array of struct, # each piece of surface with essential boundary condition gets one # element of the array with a struct with the attributes # essential.temperature=fixed (prescribed) temperature (scalar), or # handle to a function with signature # function T =f(x) # essential.fes = finite element set on the boundary to which # the condition applies # or alternatively # essential.node_list = list of nodes on the boundary to which # the condition applies # Only one of essential.fes and essential.node_list needs a given. # # For convection boundary conditions (optional): # model_data.boundary_conditions.convection = cell array of struct, # each piece of surface with convection boundary condition gets one # element of the array with a struct with the attributes # convection.ambient_temperature=ambient temperature (scalar) # convection.surface_transfer_coefficient = surface heat transfer coefficient # convection.fes = finite element set on the boundary to which # the condition applies # convection.integration_rule= integration rule # # For flux boundary conditions (optional): # model_data.boundary_conditions.flux = cell array of struct, # each piece of surface with flux boundary condition gets one # element of the array with a struct with the attributes # flux.normal_flux= normal flux component, positive when outward-bound (scalar) # flux.fes = finite element set on the boundary to which # the condition applies # flux.integration_rule= integration rule # # Control parameters: # model_data.renumber = true or false flag (default is true) # model_data.renumbering_method = optionally choose the renumbering # method (symrcm or symamd) # renumber = ~true; # Should we renumber? # if (isfield(model_data,'renumber')) # renumber =model_data.renumber; # end # Renumbering_options =struct( [] ); # # # Should we renumber the nodes to minimize the cost of the solution of # # the coupled linear algebraic equations? # if (renumber) # renumbering_method = 'symamd'; # default choice # if ( isfield(model_data,'renumbering_method')) # renumbering_method =model_data.renumbering_method;; # end # # Run the renumbering algorithm # model_data =renumber_mesh(model_data, renumbering_method);; # # Save the renumbering (permutation of the nodes) # clear Renumbering_options; Renumbering_options.node_perm =model_data.node_perm; # end timings = [] task = 'Preliminaries' start = time.time() # Extract the nodes fens = model_data['fens'] # Construct the geometry field geom = NodalField(fens=fens) # Construct the displacement field u = NodalField(dim=geom.dim, nfens=geom.nfens) # Apply the essential boundary conditions on the temperature field if 'boundary_conditions' in model_data: if 'essential' in model_data['boundary_conditions']: ebcs = model_data['boundary_conditions']['essential'] for ebc in ebcs: fenids = ebc['node_list'] value = ebc['value'] if 'value' in ebc \ else lambda xyz: 0.0 comp = ebc['comp'] for index in fenids: u.set_ebc([index], comp=comp, val=value(fens.xyz[index, :])) u.apply_ebc() # Number the equations u.numberdofs() timings.append((task, time.time() - start)) # Initialize the loads vector F = numpy.zeros((u.nfreedofs, )) # # Flux boundary condition: # if (isfield(model_data.boundary_conditions, 'flux' )) # for j=1:length(model_data.boundary_conditions.flux) # flux =model_data.boundary_conditions.flux{j}; # flux.femm = femm_heat_diffusion (struct (... # 'fes',flux.fes,... # 'integration_rule',flux.integration_rule)); # model_data.boundary_conditions.flux{j}=flux; # end # clear flux fi femm # end # task = 'Stiffness matrix' start = time.time() # Make sure the model machines are given a chance to perform # some geometry-related preparations for region in model_data['regions']: region['femm'].associate_geometry(geom) # Construct the system stiffness matrix K = csr_matrix((u.nfreedofs, u.nfreedofs)) # (all zeros, for the moment) for region in model_data['regions']: # Add up all the stiffness matrices for all the regions K += region['femm'].stiffness(geom, u) timings.append((task, time.time() - start)) # Apply the traction boundary conditions if 'boundary_conditions' in model_data: if 'traction' in model_data['boundary_conditions']: tbcs = model_data['boundary_conditions']['traction'] for tbc in tbcs: femm = tbc['femm'] fi = tbc['force_intensity'] F += femm.distrib_loads(geom, u, fi, 2) # task = 'Body loads' # start = time.time() # # for region in model_data['regions']: # Q = None # default is no internal heat generation rate # if 'heat_generation' in region: # Was it defined? # Q = region['heat_generation'] # if Q is not None: # If it was supplied, and it is nonzero, compute its contribution. # F = F + region['femm'].distrib_loads(geom, temp, Q, 3) # # timings.append((task, time.time() - start)) task = 'NZEBC loads' start = time.time() if 'boundary_conditions' in model_data: if 'essential' in model_data['boundary_conditions']: for region in model_data['regions']: # Loads due to the essential boundary conditions on the temperature field F += region['femm'].nz_ebc_loads(geom, u) timings.append((task, time.time() - start)) # # Process the flux boundary condition # if (isfield(model_data.boundary_conditions, 'flux' )) # for j=1:length(model_data.boundary_conditions.flux) # flux =model_data.boundary_conditions.flux{j}; # fi= force_intensity(struct('magn',flux.normal_flux)); # # Note the sign which reflects the formula (negative sign # # in front of the integral) # F = F - distrib_loads(flux.femm, sysvec_assembler, geom, temp, fi, 2); # end # clear flux fi # end task = 'System solution' start = time.time() # Solve for the displacement u.scatter_sysvec(spsolve(K, F)) timings.append((task, time.time() - start)) # Update the model data model_data['geom'] = geom model_data['u'] = u model_data['timings'] = timings return True