
Hi all,
I'm trying to model a magnet encased in a cube of elastomer for part of a project. I've seemingly tried everything under the sun, but ive been rather limited due to the poor interactive documentation.
I have to core problems:
Defining a region by a function: Material parameters can be defined over just a region, as such a function to define an inner regions of given bounds:
def inner_region_(coors, domain=None ,magnet=None): x, y, z = coors[:, 0], coors[:, 1], coors[:, 2]
mag_min_x, mag_max_x = str((magnet[1][0] - (magnet[0][0] / 2))), str((magnet[1][0] + (magnet[0][0] / 2)))
mag_min_y, mag_max_y = str((magnet[1][1] - (magnet[0][1] / 2))), str((magnet[1][1] + (magnet[0][1] / 2)))
mag_min_z, mag_max_z = str((magnet[1][2] - (magnet[0][2] / 2))), str((magnet[1][2] + (magnet[0][2] / 2)))
parse_def_min = 'vertices in (' + x + ' > ' + mag_min_x + ') & (' + y + ' > ' + mag_min_y + ') & (' + z + ' > ' + mag_min_z + ')'
parse_def_max = '& (' + x + ' < ' + mag_max_x + ') & (' + y + ' < ' + mag_max_y + ') & (' + z + ' < ' + mag_max_z + ')'
#pls dont hate my ugly strings :)
parse_def = parse_def_min + parse_def_max
flag = nm.where(parse_def)[0]
print(flag)
return flag
I then call the function constructor in my main, again like the tutorials:
inner_region = Function('inner_region', inner_region_, extra_args=magnet)
and define the region off the domain:
magnet_region = domain.create_region('magnet0', 'vertices by inner_region','facet')
(i think i also need to make this region a child of my Omega (all node) region)
which fails miserably, due to the Function constructor seemingly not creating a Functions instance when called, but this is just from a bit of debugging (im no expert :D)
Secondly, I can't seem to configure having two materials over differing regions in the mesh. I think this is partly due to the above but also very limited examples concerning this use case interactively. If someone could run me through this i'd be extremely grateful!
BTW Im making meshes with pymesh, so cant use groups as a work around!

Hi Joshua,
On 7/6/21 2:23 PM, Joshua colletta wrote:
Hi all,
I'm trying to model a magnet encased in a cube of elastomer for part of a project. I've seemingly tried everything under the sun, but ive been rather limited due to the poor interactive documentation.
I have to core problems:
Defining a region by a function: Material parameters can be defined over just a region, as such a function to define an inner regions of given bounds:
def inner_region_(coors, domain=None ,magnet=None): x, y, z = coors[:, 0], coors[:, 1], coors[:, 2]
mag_min_x, mag_max_x = str((magnet[1][0] - (magnet[0][0] / 2))), str((magnet[1][0] + (magnet[0][0] / 2))) mag_min_y, mag_max_y = str((magnet[1][1] - (magnet[0][1] / 2))), str((magnet[1][1] + (magnet[0][1] / 2))) mag_min_z, mag_max_z = str((magnet[1][2] - (magnet[0][2] / 2))), str((magnet[1][2] + (magnet[0][2] / 2))) parse_def_min = 'vertices in (' + x + ' > ' + mag_min_x + ') & (' + y + ' > ' + mag_min_y + ') & (' + z + ' > ' + mag_min_z + ')' parse_def_max = '& (' + x + ' < ' + mag_max_x + ') & (' + y + ' < ' + mag_max_y + ') & (' + z + ' < ' + mag_max_z + ')'
This kind of definition is used declarative region definitions, such as
domain.create_region('Gamma', 'vertices in (x < -0.4999)', ','facet')
#pls dont hate my ugly strings :)
parse_def = parse_def_min + parse_def_max flag = nm.where(parse_def)[0]
When defining region by a function, in that function (here) just use numpy:
flag = nm.where((x > mag_min_x) & (y > mag_min_y) & ....)[0]
There are no strings here, your x, y, z, and the bounds are regular arrays/numbers.
print(flag) return flag
I then call the function constructor in my main, again like the tutorials:
inner_region = Function('inner_region', inner_region_, extra_args=magnet)
and define the region off the domain:
magnet_region = domain.create_region('magnet0', 'vertices by inner_region','facet')
(i think i also need to make this region a child of my Omega (all node) region)
which fails miserably, due to the Function constructor seemingly not creating a Functions instance when called, but this is just from a bit of debugging (im no expert :D)
If the above does not help, send here a self-contained code (+ a small mesh) so that we can run it and see the problem.
Secondly, I can't seem to configure having two materials over differing regions in the mesh. I think this is partly due to the above but also very limited examples concerning this use case interactively. If someone could run me through this i'd be extremely grateful!
The easiest way is to define the two regions, let's say with names 'omega1', 'omega2', and than use something like:
m = Material('m', values={'rho': {'omega1': 2700, 'omega2': 6000}, 'E': {'omega1': 1e9, 'omega2': 1e10}})
BTW Im making meshes with pymesh, so cant use groups as a work around!
Once you are able to define the two regions, the above approach should work.
r.

Code Follows:
from argparse import ArgumentParser, RawDescriptionHelpFormatter import numpy as nm import sys import os sys.path.append('.') from sfepy.base.base import IndexedStruct from sfepy.discrete import (FieldVariable, Material, Integral, Equation, Equations, Problem, Functions) from sfepy.discrete.fem import Mesh, FEDomain, Field from sfepy.terms import Term from sfepy.discrete.conditions import Conditions, EssentialBC from sfepy.solvers.ls import ScipyDirect from sfepy.solvers.nls import Newton from sfepy.postprocess.viewer import Viewer from sfepy.mechanics.matcoefs import stiffness_from_youngpoisson from sfepy.base.conf import transform_functions
helps = { 'young': "the Young's modulus [default: %(default)s]", 'poisson': "the Poisson's ratio [default: %(default)s]", 'load': "the vertical load value (negative means compression)" " [default: %(default)s]", 'show': 'show the results figure', 'probe' : 'probe the results', 'order' : 'displacement field approximation order [default: %(default)s]', }
def inner_region_(coors, domain=None): magnet = global_magnet x, y, z = coors[:, 0], coors[:, 1], coors[:, 2] mag_min_x, mag_max_x = (magnet[1][0] - (magnet[0][0] / 2))/ 2, (magnet[1][0] + (magnet[0][0] / 2))/ 2 mag_min_y, mag_max_y = (magnet[1][1] - (magnet[0][1] / 2))/ 2, (magnet[1][1] + (magnet[0][1] / 2))/ 2 mag_min_z, mag_max_z = (magnet[1][2] - (magnet[0][2] / 2))/ 2, (magnet[1][2] + (magnet[0][2] / 2))/ 2 flag = nm.where((mag_max_x > x > mag_min_x) & (mag_max_y > y > mag_min_y) & (mag_max_z > z > mag_min_z))[0] return flag
def simulation(mesh_loc, magnet): parser = ArgumentParser(description=__doc__, formatter_class=RawDescriptionHelpFormatter) parser.add_argument('--version', action='version', version='%(prog)s') parser.add_argument('--load', metavar='float', type=float, action='store', dest='load', default=50.0, help=helps['load']) parser.add_argument('--poisson', metavar='float', type=float, action='store', dest='poisson', default=0.453, help=helps['poisson']) parser.add_argument('--young', metavar='float', type=float, action='store', dest='young', default=470.00, help=helps['young']) parser.add_argument('-s', '--show', action="store_true", dest='show', default=True, help=helps['show']) options = parser.parse_args()
global global_magnet
global_magnet = magnet
conf_functions = {
'inner_region': (inner_region_,),
}
functions = Functions.from_conf(transform_functions(conf_functions))
mesh = Mesh.from_file(mesh_loc)
domain = FEDomain('domain', mesh)
min_x, max_x = domain.get_mesh_bounding_box()[:, 0]
eps = 0.01 * (max_x - min_x)
omega = domain.create_region('Omega', 'all')
gamma1 = domain.create_region('Gamma1', 'vertices in x < %.10f' % (min_x + eps), 'facet')
gamma2 = domain.create_region('Gamma2', 'vertices in x > %.10f' % (max_x - eps), 'facet')
magnet_region = domain.create_region('magnet0', 'vertices by inner_region', 'facet', parent='Omega', functions=functions)
field = Field.from_args('fu', nm.float64, 'vector', omega, approx_order=1)
u = FieldVariable('u', 'unknown', field)
v = FieldVariable('v', 'test', field, primary_var_name='u')
integral = Integral('i', order=3)
ma = Material('ma', D=stiffness_from_youngpoisson(3, options.young, options.poisson))
m = Material('m', values={'rho': {'Omega': 2700, 'magnet0': 6000}, 'E': {'Omega': 70e3, 'magnet0': 1.6e5}})
load = Material('load', values={'val': options.load})
t1 = Term.new('dw_lin_elastic(m.D, v, u)', integral, omega, m=m, v=v, u=u)
t3 = Term.new('dw_surface_ltr( load.val, v )', integral, gamma2, load=load, v=v)
eq = Equation('balance', t1 + t3)
eqs = Equations([eq])
fix = EssentialBC('fix', gamma1, {'u.all': 0.0})
ls = ScipyDirect({})
nls_status = IndexedStruct()
nls = Newton({}, lin_solver=ls, status=nls_status)
pb = Problem('elasticity', equations=eqs)
pb.save_regions_as_groups('regions')
pb.set_bcs(ebcs=Conditions([fix]))
pb.set_solver(nls)
status = IndexedStruct()
s = pb.solve(status=status)
print('Nonlinear solver status:\n', nls_status)
print('Stationary solver status:\n', status)
pb.save_state('linear_elasticity.vtk', s)
if options.show:
view = Viewer('linear_elasticity.vtk')
view(vector_mode='warp_norm', rel_scaling=2,
is_scalar_bar=True, is_wireframe=True)
if __name__ == "__main__": magnet = [[1,1,1],[9,9,9]] ur_path_to_mesh = "" simulation(ur_path_to_mesh, magnet)
I cant seem to attach a mesh, but it takes a 10x10x10 cube as a .msh file!
nm.where() is still not behaving like i expected. I tried passing it the x,y,z vectors but still no dice. Testing the material parameters with the simple nm.where(x<3)[0] lead to a different error, stating that there is no key 'D', I believe stemming from the equations expected use of parameters in:
t1 = Term.new('dw_lin_elastic(m.D, v, u)', integral, omega, m=m, v=v, u=u)
I would like to define my materials using the stiffness_from_youngpoisson() function, is this still possible?

Hi Joshua,
I am responding in the text/code below.
On 06/07/2021 17:36, Joshua colletta wrote:
Code Follows:
from argparse import ArgumentParser, RawDescriptionHelpFormatter import numpy as nm import sys import os sys.path.append('.') from sfepy.base.base import IndexedStruct from sfepy.discrete import (FieldVariable, Material, Integral, Equation, Equations, Problem, Functions) from sfepy.discrete.fem import Mesh, FEDomain, Field from sfepy.terms import Term from sfepy.discrete.conditions import Conditions, EssentialBC from sfepy.solvers.ls import ScipyDirect from sfepy.solvers.nls import Newton from sfepy.postprocess.viewer import Viewer from sfepy.mechanics.matcoefs import stiffness_from_youngpoisson from sfepy.base.conf import transform_functions
helps = { 'young': "the Young's modulus [default: %(default)s]", 'poisson': "the Poisson's ratio [default: %(default)s]", 'load': "the vertical load value (negative means compression)" " [default: %(default)s]", 'show': 'show the results figure', 'probe' : 'probe the results', 'order' : 'displacement field approximation order [default: %(default)s]', }
def inner_region_(coors, domain=None): magnet = global_magnet x, y, z = coors[:, 0], coors[:, 1], coors[:, 2] mag_min_x, mag_max_x = (magnet[1][0] - (magnet[0][0] / 2))/ 2, (magnet[1][0] + (magnet[0][0] / 2))/ 2 mag_min_y, mag_max_y = (magnet[1][1] - (magnet[0][1] / 2))/ 2, (magnet[1][1] + (magnet[0][1] / 2))/ 2 mag_min_z, mag_max_z = (magnet[1][2] - (magnet[0][2] / 2))/ 2, (magnet[1][2] + (magnet[0][2] / 2))/ 2 flag = nm.where((mag_max_x > x > mag_min_x) & (mag_max_y > y > mag_min_y) & (mag_max_z > z > mag_min_z))[0]
NumPy arrays cannot be compared using a < b < c syntax, you have to use (a < b) & (b < c):
flag = nm.where((mag_max_x > x) & (x > mag_min_x) & (mag_max_y > y) & (y > mag_min_y) & (mag_max_z > z) & (z > mag_min_z))[0]
return flag
def simulation(mesh_loc, magnet): parser = ArgumentParser(description=__doc__, formatter_class=RawDescriptionHelpFormatter) parser.add_argument('--version', action='version', version='%(prog)s') parser.add_argument('--load', metavar='float', type=float, action='store', dest='load', default=50.0, help=helps['load']) parser.add_argument('--poisson', metavar='float', type=float, action='store', dest='poisson', default=0.453, help=helps['poisson']) parser.add_argument('--young', metavar='float', type=float, action='store', dest='young', default=470.00, help=helps['young']) parser.add_argument('-s', '--show', action="store_true", dest='show', default=True, help=helps['show']) options = parser.parse_args()
global global_magnet global_magnet = magnet conf_functions = { 'inner_region': (inner_region_,), } functions = Functions.from_conf(transform_functions(conf_functions)) mesh = Mesh.from_file(mesh_loc) domain = FEDomain('domain', mesh) min_x, max_x = domain.get_mesh_bounding_box()[:, 0] eps = 0.01 * (max_x - min_x) omega = domain.create_region('Omega', 'all') gamma1 = domain.create_region('Gamma1', 'vertices in x < %.10f' % (min_x + eps), 'facet') gamma2 = domain.create_region('Gamma2', 'vertices in x > %.10f' % (max_x - eps), 'facet') magnet_region = domain.create_region('magnet0', 'vertices by inner_region', 'facet', parent='Omega', functions=functions) field = Field.from_args('fu', nm.float64, 'vector', omega, approx_order=1) u = FieldVariable('u', 'unknown', field) v = FieldVariable('v', 'test', field, primary_var_name='u') integral = Integral('i', order=3) ma = Material('ma', D=stiffness_from_youngpoisson(3, options.young, options.poisson)) m = Material('m', values={'rho': {'Omega': 2700, 'magnet0': 6000}, 'E': {'Omega': 70e3, 'magnet0': 1.6e5}})
This was just an example of how to define region-dependent values. In your particular case, you can use something like:
m = Material('m', values={
'D': {
'Omega': stiffness_from_youngpoisson(3, options.young,
options.poisson), 'magnet0': stiffness_from_youngpoisson(3, options.young2, options.poisson2) } })
- the young2, poisson2 options would need to be added.
load = Material('load', values={'val': options.load}) t1 = Term.new('dw_lin_elastic(m.D, v, u)', integral, omega, m=m, v=v, u=u) t3 = Term.new('dw_surface_ltr( load.val, v )', integral, gamma2, load=load, v=v) eq = Equation('balance', t1 + t3) eqs = Equations([eq]) fix = EssentialBC('fix', gamma1, {'u.all': 0.0}) ls = ScipyDirect({}) nls_status = IndexedStruct() nls = Newton({}, lin_solver=ls, status=nls_status) pb = Problem('elasticity', equations=eqs) pb.save_regions_as_groups('regions') pb.set_bcs(ebcs=Conditions([fix])) pb.set_solver(nls) status = IndexedStruct() s = pb.solve(status=status) print('Nonlinear solver status:\n', nls_status) print('Stationary solver status:\n', status) pb.save_state('linear_elasticity.vtk', s) if options.show: view = Viewer('linear_elasticity.vtk') view(vector_mode='warp_norm', rel_scaling=2, is_scalar_bar=True, is_wireframe=True)
if __name__ == "__main__": magnet = [[1,1,1],[9,9,9]] ur_path_to_mesh = "" simulation(ur_path_to_mesh, magnet)
I cant seem to attach a mesh, but it takes a 10x10x10 cube as a .msh file!
No problem, I have generated a test mesh using:
python ./script/blockgen.py -d 10,10,10 -c 5,5,5 -s 31,31,31 -o mesh.vtk
nm.where() is still not behaving like i expected. I tried passing it the x,y,z vectors but still no dice.
See the comment in the code above.
Testing the material parameters with the simple nm.where(x<3)[0] lead to a different error, stating that there is no key 'D', I believe stemming from the equations expected use of parameters in:
t1 = Term.new('dw_lin_elastic(m.D, v, u)', integral, omega, m=m, v=v, u=u)
I would like to define my materials using the stiffness_from_youngpoisson() function, is this still possible?
Yes, see above again.
r.
participants (2)
-
Joshua colletta
-
Robert Cimrman