def test_first_example(self): import math import numpy from numpy import array from spyfe.materials.mat_heatdiff import MatHeatDiff from spyfe.fesets.surfacelike import FESetT3 from spyfe.femms.femm_heatdiff import FEMMHeatDiff from spyfe.fields.nodal_field import NodalField from spyfe.integ_rules import TriRule from spyfe.fenode_set import FENodeSet # These are the constants in the problem, k is kappa a = 2.5 # radius on the columnthe dy = a / 2 * math.sin(15. / 180 * math.pi) dx = a / 2 * math.cos(15. / 180 * math.pi) Q = 4.5 # internal heat generation rate k = 1.8 # thermal conductivity m = MatHeatDiff(thermal_conductivity=array([[k, 0.0], [0.0, k]])) Dz = 1.0 # thickness of the slice xall = array([[0, 0], [dx, -dy], [dx, dy], [2 * dx, -2 * dy], [2 * dx, 2 * dy]]) fes = FESetT3(array([[1, 2, 3], [2, 4, 5], [2, 5, 3]]) - 1) femm = FEMMHeatDiff(material=m, fes=fes, integration_rule=TriRule(npts=1)) fens = FENodeSet(xyz=xall) geom = NodalField(fens=fens) temp = NodalField(nfens=xall.shape[0], dim=1) temp.set_ebc([3, 4]) temp.apply_ebc() temp.numberdofs(node_perm=[1, 2, 0, 4, 3]) print(temp.dofnums) K = femm.conductivity(geom, temp) print(K)
def nodal_field_from_integr_points(self, geom, un1, un, dt=0.0, dtempn1=None, outcs=CSys(), output=OUTPUT_CAUCHY, component=(0,)): """Create a nodal field from quantities at integration points. The procedure is the universe-distance interpolation. :param geom: Geometry field. :param un1: Displacement field at the time t_n+1. :param un: Displacement field at time t_n. :param dt: Time step from t_n to t_n+1. :param dtempn1: Temperature increment field or None. :param outcs: Output coordinate system. :param output: Output quantity (enumeration). :param component: Which component of the output quantity? :return: nodal field """ # Container of intermediate results sum_inv_dist = numpy.zeros((geom.nfens,)) sum_quant_inv_dist = numpy.zeros((geom.nfens, len(component))) fld = NodalField(nfens=geom.nfens, dim=len(component)) # This is an inverse-distance interpolation inspector. def idi(idat, out, xyz, u, pc): x, conn = idat da = x - numpy.ones((x.shape[0], 1)) * xyz d = numpy.sum(da ** 2, axis=1) zi = d == 0 d[zi] = min(d[~zi]) / 1.e9 invd = numpy.reshape(1. / d, (x.shape[0], 1)) quant = numpy.reshape(out[component], (1, len(component))) sum_quant_inv_dist[conn, :] += invd * quant sum_inv_dist[conn] += invd.ravel() return # Loop over cells to interpolate to nodes for i in range(self.fes.conn.shape[0]): x1 = geom.values[self.fes.conn[i, :], :] idat1 = (x1, self.fes.conn[i, :]) self.inspect_integration_points([i], idi, idat1, geom, un1, un, dt, dtempn1, outcs, output) # compute the field data array nzi = ~(sum_inv_dist == 0) for j in range(len(component)): fld.values[nzi, j] = sum_quant_inv_dist[nzi, j] / sum_inv_dist[nzi] return fld
def test_nastran_importer(self): from spyfe.fields.nodal_field import NodalField from spyfe.meshing.importers import nastran_importer from spyfe.fesets.volumelike import FESetT4, FESetT10 from spyfe.meshing.exporters.vtkexporter import vtkexport fens, feslist = nastran_importer.import_mesh('Slot-coarser.nas') print(feslist[0].count()) geom = NodalField(fens=fens) vtkexport("test_nastran_importer", feslist[0], geom) print('Done')
def test_Abaqus_importer(self): from spyfe.fields.nodal_field import NodalField from spyfe.meshing.importers import abaqus_importer from spyfe.meshing.exporters.vtkexporter import vtkexport fens, feslist = abaqus_importer.import_mesh('LE11_H20.inp') for fes in feslist: print(fes.count()) fes = feslist[0] geom = NodalField(fens=fens) vtkexport("test_Abaqus_importer", fes, geom) print('Done')
def test_Q8_meshing(self): from spyfe.fields.nodal_field import NodalField from spyfe.meshing.exporters.vtkexporter import vtkexport from spyfe.meshing.generators.quadrilaterals import q4_block, q4_to_q8 N = 2 Length, Width, nL, nW = 10.0, 7.0, N, N fens, fes = q4_block(Length, Width, nL, nW) fens, fes = q4_to_q8(fens, fes) print(fes.conn) geom = NodalField(fens=fens) vtkexport("test_Q8_meshing_mesh", fes, geom)
def test_connection_matrix(self): from context import spyfe from spyfe.meshing.generators.triangles import t3_ablock from spyfe.femms.femm_base import FEMMBase from spyfe.fields.nodal_field import NodalField from spyfe.integ_rules import TriRule N = 5 Length, Width, nL, nW = 1.0, 1.0, N, N fens, fes = t3_ablock(Length, Width, nL, nW) geom = NodalField(fens=fens) femm = FEMMBase(fes=fes, integration_rule=TriRule(npts=1)) S = femm.connection_matrix(geom)
def plot_mesh(model_data): """Generate a VTK file for the plotting of the mesh. :param model_data: model dictionary, the following keys need to have values: model_data['fens'] model_data['regions'] :return: Boolean """ file = 'mesh' if 'postprocessing' in model_data: if 'file' in model_data['postprocessing']: file = model_data['postprocessing']['file'] fens = model_data['fens'] geom = NodalField(fens=fens) for r in range(len(model_data['regions'])): region = model_data['regions'][r] femm = region['femm'] vtkexport(file + str(r), femm.fes, geom) return True
def test_fusing_nodes(self): import numpy from spyfe.fields.nodal_field import NodalField from spyfe.meshing.exporters.vtkexporter import vtkexport from spyfe.meshing.generators.quadrilaterals import q4_block, q4_to_q8 from spyfe.meshing.modification import fuse_nodes, merge_meshes N = 10 Length, Width, nL, nW = 2.0, 3.0, N, N fens, fes = q4_block(Length, Width, nL, nW) fens1, fes1 = q4_to_q8(fens, fes) fens1.xyz[:, 0] += Length fens, fes = q4_block(Length, Width, nL, nW) fens2, fes2 = q4_to_q8(fens, fes) tolerance = Length / 1000 fens, new_indexes_of_fens1_nodes = fuse_nodes(fens1, fens2, tolerance) print(fens.xyz) print(new_indexes_of_fens1_nodes) fens, fes1, fes2 = merge_meshes(fens1, fes1, fens2, fes2, tolerance) fes = fes1.cat(fes2) print(fens.xyz) print(fes.conn) geom = NodalField(fens=fens) vtkexport("test_fusing_nodes_mesh", fes, geom)
# 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 = 4 xs = numpy.linspace(0.0, 1.0, N + 1) ys = numpy.linspace(0.0, 1.0, N + 1) fens, fes = q4_blockx(xs, ys) fens, fes = q4_to_q8(fens, fes) 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() 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)
nu = 0.3 alpha = 2.3e-4 m = MatDeforTriaxLinearIso(e=E, nu=nu, alpha=alpha) start = time.time() fens, feslist = abaqus_importer.import_mesh('LE11_H20_90deg.inp') # Account for the instance rotation fens = rotate_mesh(fens, math.pi * 90. / 180 * numpy.array([1.0, 0.0, 0.0]), numpy.array([0.0, 0.0, 0.0])) for fes in feslist: print(fes.count()) fes = feslist[0] scipy.io.savemat('LE11_H20_90deg.mat', {'xyz': fens.xyz, 'conn': fes.conn}) print('Mesh import', time.time() - start) geom = NodalField(fens=fens) u = NodalField(nfens=fens.count(), dim=3) htol = 1.0 / 1000 cn = fenode_select(fens, plane=([0, 0, 0.], [0., 0., -1.]), inflate=htol) for j in cn: u.set_ebc([j], comp=2, val=0.0) cn = fenode_select(fens, plane=([0, 0, 1.79], [0., 0., -1.]), inflate=htol) for j in cn: u.set_ebc([j], comp=2, val=0.0) cn = fenode_select(fens, plane=([0, 0, 0], [0., +1., 0.]), inflate=htol) for j in cn: u.set_ebc([j], comp=1, val=0.0) cn = fenode_select(fens, plane=([0, 0, 0], [+1., 0., 0.]), inflate=htol) for j in cn: u.set_ebc([j], comp=0, val=0.0) u.apply_ebc()
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
def nodal_field_from_integr_points_spr(self, geom, un1, un, dt=0.0, dtempn1=None, outcs=CSys(), output=OUTPUT_CAUCHY, component=(0,)): """Create a nodal field from quantities at integration points. The procedure is the Super-convergent Patch Recovery. :param geom: Geometry field. :param un1: Displacement field at the time t_n+1. :param un: Displacement field at time t_n. :param dt: Time step from t_n to t_n+1. :param dtempn1: Temperature increment field or None. :param outcs: Output coordinate system. :param output: Output quantity (enumeration). :param component: Which component of the output quantity? :return: nodal field """ fes = self.fes # Make the inverse map from finite element nodes to finite elements femap = fenode_to_fe_map(geom.nfens, fes.conn) fld = NodalField(nfens=geom.nfens, dim=len(component)) # This is an inverse-distance interpolation inspector. def idi(idat, out, xyz, u, pc): idat.append((numpy.array(out), xyz)) def spr(idat, xc): """Super-convergent Patch Recovery. :param idat: List of integration point data. :param xc: Location at which the quantities to be recovered. :return: Recovered quantity. """ n = len(idat) if n == 0: # nothing can be done raise Exception('No data for SPR') elif n == 1: # we got a single value: return it out, xyz = idat[0] sproutput = out.ravel() / n else: # attempt to solve the least-squares problem out, xyz = idat[0] dim = xyz.size # the number of modeling dimensions (1, 2, 3) nc = out.size na = dim + 1 if (n >= na): A = numpy.zeros((na, na)) b = numpy.zeros((na, nc)) pk = numpy.zeros((na, 1)) pk[0] = 1.0 for k in range(n): out, xyz = idat[k] out.shape = (1, nc) xk = xyz - xc pk[1:] = xk[:].reshape(dim, 1) A += pk * pk.T b += pk * out try: a = numpy.linalg.solve(A, b) # xk = xc - xc # p = [1, xk] sproutput = a[0, :].ravel() except: # not enough to solve the least-squares problem: compute simple average out, xyz = idat[0] sproutput = out / n for k in range(1, n): out, xyz = idat[k] sproutput += out / n sproutput = sproutput.ravel() else: # not enough to solve the least-squares problem: compute simple average out, xyz = idat[0] sproutput = out / n for k in range(1, n): out, xyz = idat[k] sproutput += out / n sproutput = sproutput.ravel() return sproutput # Loop over nodes, and for each visit the connected FEs for i in range(geom.nfens): idat = [] xc = geom.values[i, :] # location of the current node # construct the list of the relevant integr points # and the values at these points idat = self.inspect_integration_points(femap[i], idi, idat, geom, un1, un, dt, dtempn1, outcs, output) out1 = spr(idat, xc) fld.values[i, :] = out1[:] return fld
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.fields.gen_field import GenField from spyfe.integ_rules import TriRule from spyfe.force_intensity import ForceIntensity from scipy.sparse.linalg import spsolve, minres import time from spyfe.meshing.exporters.vtkexporter import vtkexport Length, Width, nL, nW = 10.0, 10.0, 7, 8 fens, fes = t3_ablock(Length, Width, nL, nW) geom = NodalField(nfens=fens.count(), dim=3) for index in range(fens.count()): for j in range(2): geom.values[index, j] = fens.xyz[index, j] vtkexport("show_basis_funcs-geom", fes, geom) bf1 = GenField(data=geom.values) bf1.values[0, 2] = 1.0 vtkexport("show_basis_funcs-bf1", fes, bf1) bf13 = GenField(data=geom.values) bf13.values[12, 2] = 1.0 vtkexport("show_basis_funcs-bf13", fes, bf13) bf16 = GenField(data=geom.values) bf16.values[15, 2] = 1.0
L = 50 # nW, nL, nH = 20, 20, 20 nW, nL, nH = 4, 20, 4 htol = min(L, H, W) / 1000 magn = -0.2 * 12.2334 / 4 Force = magn * W * H * 2 Force * L**3 / (3 * E * W * H**3 * 2 / 12) uzex = -12.0935378981478 m = MatDeforTriaxLinearIso(e=E, nu=nu) start = time.time() fens, fes = h8_block(W, L, H, nW, nL, nH) fens, fes = h8_to_h20(fens, fes) print(fes.conn.shape) print('Mesh generation', time.time() - start) geom = NodalField(fens=fens) u = NodalField(nfens=fens.count(), dim=3) cn = fenode_select(fens, box=numpy.array([0, W, 0, 0, 0, H]), inflate=htol) for j in cn: u.set_ebc([j], comp=0, val=0.0) u.set_ebc([j], comp=1, val=0.0) u.set_ebc([j], comp=2, val=0.0) cn = fenode_select(fens, box=numpy.array([W, W, 0, L, 0, H]), inflate=htol) for j in cn: u.set_ebc([j], comp=0, val=0.0) u.apply_ebc() femm = FEMMDeforLinear(material=m, fes=fes, integration_rule=GaussRule(dim=3, order=2)) femm.associate_geometry(geom) S = femm.connection_matrix(geom)
start0 = time.time() # These are the constants in the problem, k is kappa boundaryf = lambda x, y, z: 1.0 + x**2 + 2 * y**2 Q = -6 # internal heat generation rate k = 1.0 # thermal conductivity m = MatHeatDiff(thermal_conductivity=k * numpy.identity(3)) start = time.time() N = 4 xs = numpy.linspace(0.0, 1.0, N + 1) ys = numpy.linspace(0.0, 1.0, N + 1) zs = numpy.linspace(0.0, 1.0, N + 1) fens, fes = h8_blockx(xs, ys, zs) fens, fes = h8_to_h20(fens, fes) fes.gradbfunpar(numpy.array([0, 0, 0])) geom = NodalField(fens=fens) vtkexport("Poisson_fe_H20_mesh", fes, geom) print('Mesh generation', time.time() - start) bfes = mesh_boundary(fes) cn = connected_nodes(bfes) temp = NodalField(nfens=fens.count(), dim=1) for j in cn: temp.set_ebc([j], val=boundaryf(fens.xyz[j, 0], fens.xyz[j, 1], fens.xyz[j, 2])) temp.apply_ebc() femm = FEMMHeatDiff(material=m, fes=fes, integration_rule=GaussRule(dim=3, order=3)) S = femm.connection_matrix(geom)
E = 1.0 nu = 0.499 rho = 1.0 a = 1.0 b = a h = a htol = h / 1000 na, nb, nh = 5, 5, 5 m = MatDeforTriaxLinearIso(rho=rho, e=E, nu=nu) start = time.time() fens, fes = h8_block(a, b, h, na, nb, nh) fens, fes = h8_to_h20(fens, fes) print('Mesh generation', time.time() - start) geom = NodalField(fens=fens) u = NodalField(nfens=fens.count(), dim=3) u.apply_ebc() femmk = FEMMDeforLinear(material=m, fes=fes, integration_rule=GaussRule(dim=3, order=2)) femmk.associate_geometry(geom) u.numberdofs() print('Number of degrees of freedom', u.nfreedofs) start = time.time() K = femmk.stiffness(geom, u) K = (K.T + K) / 2.0 print('Stiffness assembly', time.time() - start) start = time.time() femmm = FEMMDeforLinear(material=m, fes=fes,
E = 200e9 nu = 0.3 rho = 8000 a = 10.0 b = a h = 0.05 htol = h / 1000 na, nb, nh = 6,6,4 m = MatDeforTriaxLinearIso(rho=rho, e=E, nu=nu) start = time.time() fens, fes = h8_block(a, b, h, na, nb, nh) fens, fes = h8_to_h20(fens, fes) print('Mesh generation', time.time() - start) geom = NodalField(fens=fens) u = NodalField(nfens=fens.count(), dim=3) cn = fenode_select(fens, box=numpy.array([0, 0, 0, b, 0, h]), inflate=htol) for j in cn: u.set_ebc([j], comp=0, val=0.0) u.set_ebc([j], comp=1, val=0.0) u.set_ebc([j], comp=2, val=0.0) u.apply_ebc() femmk = FEMMDeforLinear(material=m, fes=fes, integration_rule=GaussRule(dim=3, order=2)) femmk.associate_geometry(geom) u.numberdofs() print('Number of degrees of freedom', u.nfreedofs) start = time.time() K = femmk.stiffness(geom, u) K = (K.T + K)/2.0 print('Stiffness assembly', time.time() - start)
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]]))