def jT_lam( name="jT", sigma_el=1.0, # electrical conductivity sigma_th=0.1, # thermal conductivity c_heat=1.0 / 10., # heat capacity T_initial=300.0, mesh=None, ksp_tolerances={}): print "Debug: c_heat = %f, sigma_el=%f, sigma_th=%f" % (c_heat, sigma_el, sigma_th) #sys.exit(0) intensive_params = ["TIME", "Phi_ext"] raw_mesh = mesh.raw_mesh dim = ocaml.mesh_dim(raw_mesh) def get_tol(name): if ksp_tolerances.has_key(name): ksp_tolerances[name] else: None elem_V = ocaml.make_element("V", [dim], dim, 1) elem_S = ocaml.make_element("S", [], dim, 1) def fun_outer_region(coords): if coords[0] < -499.9 or coords[0] > 499.9: return -2 else: return -1 def fun_T_initial(field, pos): #print ("SAMPLING field %s AT: %s" % (field,pos)) return T_initial def fun_T_initial_debug(field, pos): print("SAMPLING field %s AT: %s" % (field, pos)) # return T_initial x, y, z = pos if x < 0: return 300 else: return 100 return 0.0 #should not occur mwe_V = ocaml.make_mwe("V", raw_mesh, [(0, ocaml.empty_element), (1, elem_V)], [fun_outer_region]) mwe_S = ocaml.make_mwe("S", raw_mesh, [(0, ocaml.empty_element), (1, elem_S)], [fun_outer_region]) mwe_j = ocaml.mwe_sibling(mwe_V, "j", "j/V", [("V", "j")]) mwe_phi = ocaml.mwe_sibling(mwe_S, "phi", "phi/S", [("S", "phi")]) mwe_rho = ocaml.mwe_sibling(mwe_S, "rho", "rho/S", [("S", "rho")]) mwe_T = ocaml.mwe_sibling(mwe_S, "T", "T/S", [("S", "T")]) mwe_Laplace_T = ocaml.mwe_sibling(mwe_S, "Laplace_T", "Laplace_T/S", [("S", "Laplace_T")]) mwe_dTdt = ocaml.mwe_sibling(mwe_S, "dTdt", "dTdt/S", [("S", "dTdt")]) master_mwes_and_fields_by_name = {} master_mwes_and_fields_by_name["T"] = (mwe_T, ocaml.raw_make_field( mwe_T, [fun_T_initial], "", "")) master_mwes_and_fields_by_name["Laplace_T"] = (mwe_j, ocaml.raw_make_field( mwe_Laplace_T, [], "", "")) master_mwes_and_fields_by_name["j"] = (mwe_j, ocaml.raw_make_field( mwe_j, [], "", "")) master_mwes_and_fields_by_name["phi"] = (mwe_phi, ocaml.raw_make_field( mwe_phi, [], "", "")) master_mwes_and_fields_by_name["rho"] = (mwe_rho, ocaml.raw_make_field( mwe_rho, [], "", "")) # Note that at present, SITE_WISE does not work properly with restricted vectors, # so we will have to set the heating voltage throughout the sample, and throw away # the values inside the bulk then. ccode_heating = """ if(have_phi) { if(COORDS(0)<0) {phi= 0.5*Phi_ext;} else {phi= -0.5*Phi_ext;} } """ # Note ad resistive heating: integrated power generation = U*I. # Local power generation = E*j. As j = sigma*E, we get p = j^2/sigma, # so the contribution to dT/dt is j^2/sigma. eq_dTdt = """%%range k:%d; dTdt <- (%.8f)*Laplace_T + (%.8f)*j(k)*j(k); """ % (dim, sigma_th / c_heat, 1.0 / (c_heat * sigma_el)) print "DDD eq_dTdt: ", eq_dTdt lam_mwes = { "j": mwe_j, "phi": mwe_phi, "rho": mwe_rho, "T": mwe_T, "Laplace_T": mwe_Laplace_T, "dTdt": mwe_dTdt, } lam_vectors = { "v_j": nlam.lam_vector(name="v_j", mwe_name="j"), "v_phi": nlam.lam_vector(name="v_phi", mwe_name="phi"), "v_phi_boundary": nlam.lam_vector(name="v_phi_boundary", mwe_name="phi", restriction="phi[boundary=-2/*]"), "v_rho": nlam.lam_vector(name="v_rho", mwe_name="rho"), "v_T": nlam.lam_vector(name="v_T", mwe_name="T"), "v_Laplace_T": nlam.lam_vector(name="v_Laplace_T", mwe_name="Laplace_T"), "v_dTdt": nlam.lam_vector(name="v_dTdt", mwe_name="dTdt"), } lam_operators={\ "op_j_phi":nlam.lam_operator("op_j_phi","j","phi", "%g*<j(k) || d/dxk phi>, k:%d" % (sigma_el,dim)), "op_Laplace_T":nlam.lam_operator("op_Laplace_T","Laplace_T","T", "-<d/dxk Laplace_T || d/dxk T>, k:%d" % dim ), # Tricky issue: we have DBC along the contacts and NBC everywhere else. # XXX REPAIR: LHS field should be named "rho". # XXX Can our "left field equals right field" syntax already cope with that? "op_laplace_DNBC":nlam.lam_operator("op_laplace_DNBC","phi","phi", """ -<d/dxk phi[vol] || d/dxk phi[vol]> -<d/dxk phi[boundary=-1/1] || d/dxk phi[vol]> -<d/dxk phi[boundary=-1/1] || d/dxk phi[boundary=-1/1]> -<d/dxk phi[vol] || d/dxk phi[boundary=-1/1]> ;phi[boundary=-2/*]=phi[boundary=-2/*], k:%d""" %dim), #"op_laplace_DNBC":nlam.lam_operator("op_laplace_DNBC","phi","phi", # """ -<d/dxk phi || d/dxk phi> # ;phi[boundary=-2/*]=phi[boundary=-2/*], k:%d""" %dim), "op_load_DBC":nlam.lam_operator("op_load_DBC","rho","phi", "<d/dxk rho || d/dxk phi[boundary=-2/*]>;(L||R)=(*||phi[boundary=-2/*]), k:%d" %dim), } lam_ksps = { "solve_laplace_DNBC": nlam.lam_ksp( name="solve_laplace_DNBC", matrix_name="op_laplace_DNBC", ksp_type="gmres", pc_type="ilu", initial_guess_nonzero=True, rtol=get_tol("DNBC.rtol"), atol=get_tol("DNBC.atol"), dtol=get_tol("DNBC.dtol"), maxits=get_tol("DNBC.maxits"), ) } lam_local = { "local_dTdt": nlam.lam_local("local_dTdt", field_mwes=["dTdt", "Laplace_T", "j"], equation=eq_dTdt), "local_set_phi_heating": nlam.lam_local("local_set_phi_heating", aux_args=intensive_params, field_mwes=["phi"], c_code=ccode_heating) } lam_jacobi = { "jacobian": nlam.lam_jplan( "jacobian", "dTdt", ["T", "Laplace_T", "j"], [ [], [ # all contributions to d Laplace_T/dT ("operator", "op_Laplace_T") ], [ # all contributions to dj/dT - none in this model. ] ], eq_dTdt) } lam_programs = { "update_dTdt": nlam.lam_program( "update_dTdt", commands=[ ["TSTART", "update_dTdt"], ["GOSUB", "set_Laplace_T"], ["GOSUB", "set_j"], [ "SITE-WISE-IPARAMS", "local_dTdt", ["v_dTdt", "v_Laplace_T", "v_j"], [] ], # ["DEBUG","v_dTdt","v_dTdt",0], # seems okay! ["TSTOP", "update_dTdt"], ]), "set_Laplace_T": nlam.lam_program( "set_Laplace_T", commands=[ ["TSTART", "Laplace_T"], ["SM*V", "op_Laplace_T", "v_T", "v_Laplace_T"], ["CFBOX", "Laplace_T", "v_Laplace_T"], # ["DEBUG","v_Laplace_T","v_Laplace_T",0], ["TSTOP", "Laplace_T"] ]), "set_j": nlam.lam_program( "set_j", commands=[ ["TSTART", "j"], ["SITE-WISE-IPARAMS", "local_set_phi_heating", ["v_phi"], []], [ "PULL-FEM", "phi", "phi[boundary=-2/*]", "v_phi", "v_phi_boundary" ], # ["DEBUG","v_phi_boundary","v_phi_boundary",0], ["SM*V", "op_load_DBC", "v_phi_boundary", "v_rho"], # ["DEBUG","v_rho","v_rho",0], ["SCALE", "v_phi", 0.0], ["SOLVE", "solve_laplace_DNBC", "v_rho", "v_phi"], [ "PUSH-FEM", "phi", "phi[boundary=-2/*]", "v_phi_boundary", "v_phi" ], # ^ This is to add proper boundary values! ["SM*V", "op_j_phi", "v_phi", "v_j"], # ["DEBUG","v_phi","v_phi",0], # ["DEBUG","v_j","v_j",0], ["CFBOX", "j", "v_j"], ["TSTOP", "j"] ]), "execute_jplan": nlam.lam_program( "execute_jplan", commands=[["TSTART", "execute_jplan"], ["GOSUB", "set_Laplace_T"], ["GOSUB", "set_j"], ["JPLAN", "jacobian", ["v_T", "v_Laplace_T", "v_j"]], ["TSTOP", "execute_jplan"]]), "rhs": nlam.lam_program( "rhs", args_fields=[["arg_dTdt", "dTdt"], ["arg_T", "T"]], # [arg_name,mwe_name] commands=[ ["TSTART", "rhs"], ["DISTRIB", "arg_T", "v_T"], # ["DEBUG","v_T","v_T",0], ["GOSUB", "update_dTdt"], ["COLLECT", "arg_dTdt", "v_dTdt"], # ["DEBUG","v_dTdt","v_dTdt",0], ["TSTOP", "rhs"] ]), } lam = nlam.make_linalg_machine(name, intensive_params=intensive_params, mwes=lam_mwes.values(), vectors=lam_vectors.values(), operators=lam_operators.values(), ksps=lam_ksps.values(), local_operations=lam_local.values(), jacobi_plans=lam_jacobi.values(), programs=lam_programs.values()) return (lam, master_mwes_and_fields_by_name)
def _build_lam_program(self): commands = _expand_commands(self.commands) return nlam.lam_program(self.get_prog_name(), commands=commands)
def jT_lam(name="jT", sigma_el=1.0, # electrical conductivity sigma_th=0.1, # thermal conductivity c_heat=1.0/10.,# heat capacity T_initial=300.0, mesh=None, ksp_tolerances={} ): print "Debug: c_heat = %f, sigma_el=%f, sigma_th=%f" % (c_heat,sigma_el,sigma_th) #sys.exit(0) intensive_params=["TIME","Phi_ext"] raw_mesh=mesh.raw_mesh dim = ocaml.mesh_dim(raw_mesh) def get_tol(name): if ksp_tolerances.has_key(name): ksp_tolerances[name] else: None elem_V = ocaml.make_element("V", [dim], dim, 1) elem_S = ocaml.make_element("S", [], dim, 1) def fun_outer_region(coords): if coords[0]<-499.9 or coords[0]>499.9: return -2 else: return -1 def fun_T_initial(field,pos): #print ("SAMPLING field %s AT: %s" % (field,pos)) return T_initial def fun_T_initial_debug(field,pos): print ("SAMPLING field %s AT: %s" % (field,pos)) # return T_initial x,y,z=pos if x < 0: return 300 else: return 100 return 0.0 #should not occur mwe_V=ocaml.make_mwe("V",raw_mesh,[(0,ocaml.empty_element),(1,elem_V)],[fun_outer_region]) mwe_S=ocaml.make_mwe("S",raw_mesh,[(0,ocaml.empty_element),(1,elem_S)],[fun_outer_region]) mwe_j=ocaml.mwe_sibling(mwe_V,"j","j/V",[("V","j")]) mwe_phi=ocaml.mwe_sibling(mwe_S,"phi","phi/S",[("S","phi")]) mwe_rho=ocaml.mwe_sibling(mwe_S,"rho","rho/S",[("S","rho")]) mwe_T=ocaml.mwe_sibling(mwe_S,"T","T/S",[("S","T")]) mwe_Laplace_T=ocaml.mwe_sibling(mwe_S,"Laplace_T","Laplace_T/S",[("S","Laplace_T")]) mwe_dTdt=ocaml.mwe_sibling(mwe_S,"dTdt","dTdt/S",[("S","dTdt")]) master_mwes_and_fields_by_name={} master_mwes_and_fields_by_name["T"]=(mwe_T,ocaml.raw_make_field(mwe_T,[fun_T_initial],"","")) master_mwes_and_fields_by_name["Laplace_T"]=(mwe_j,ocaml.raw_make_field(mwe_Laplace_T,[],"","")) master_mwes_and_fields_by_name["j"]=(mwe_j,ocaml.raw_make_field(mwe_j,[],"","")) master_mwes_and_fields_by_name["phi"]=(mwe_phi,ocaml.raw_make_field(mwe_phi,[],"","")) master_mwes_and_fields_by_name["rho"]=(mwe_rho,ocaml.raw_make_field(mwe_rho,[],"","")) # Note that at present, SITE_WISE does not work properly with restricted vectors, # so we will have to set the heating voltage throughout the sample, and throw away # the values inside the bulk then. ccode_heating= """ if(have_phi) { if(COORDS(0)<0) {phi= 0.5*Phi_ext;} else {phi= -0.5*Phi_ext;} } """ # Note ad resistive heating: integrated power generation = U*I. # Local power generation = E*j. As j = sigma*E, we get p = j^2/sigma, # so the contribution to dT/dt is j^2/sigma. eq_dTdt="""%%range k:%d; dTdt <- (%.8f)*Laplace_T + (%.8f)*j(k)*j(k); """ % (dim, sigma_th/c_heat, 1.0/(c_heat*sigma_el)) print "DDD eq_dTdt: ",eq_dTdt lam_mwes={"j":mwe_j, "phi":mwe_phi, "rho":mwe_rho, "T":mwe_T, "Laplace_T":mwe_Laplace_T, "dTdt":mwe_dTdt, } lam_vectors={"v_j":nlam.lam_vector(name="v_j",mwe_name="j"), "v_phi":nlam.lam_vector(name="v_phi",mwe_name="phi"), "v_phi_boundary":nlam.lam_vector(name="v_phi_boundary", mwe_name="phi", restriction="phi[boundary=-2/*]"), "v_rho":nlam.lam_vector(name="v_rho",mwe_name="rho"), "v_T":nlam.lam_vector(name="v_T",mwe_name="T"), "v_Laplace_T":nlam.lam_vector(name="v_Laplace_T",mwe_name="Laplace_T"), "v_dTdt":nlam.lam_vector(name="v_dTdt",mwe_name="dTdt"), } lam_operators={\ "op_j_phi":nlam.lam_operator("op_j_phi","j","phi", "%g*<j(k) || d/dxk phi>, k:%d" % (sigma_el,dim)), "op_Laplace_T":nlam.lam_operator("op_Laplace_T","Laplace_T","T", "-<d/dxk Laplace_T || d/dxk T>, k:%d" % dim ), # Tricky issue: we have DBC along the contacts and NBC everywhere else. # XXX REPAIR: LHS field should be named "rho". # XXX Can our "left field equals right field" syntax already cope with that? "op_laplace_DNBC":nlam.lam_operator("op_laplace_DNBC","phi","phi", """ -<d/dxk phi[vol] || d/dxk phi[vol]> -<d/dxk phi[boundary=-1/1] || d/dxk phi[vol]> -<d/dxk phi[boundary=-1/1] || d/dxk phi[boundary=-1/1]> -<d/dxk phi[vol] || d/dxk phi[boundary=-1/1]> ;phi[boundary=-2/*]=phi[boundary=-2/*], k:%d""" %dim), #"op_laplace_DNBC":nlam.lam_operator("op_laplace_DNBC","phi","phi", # """ -<d/dxk phi || d/dxk phi> # ;phi[boundary=-2/*]=phi[boundary=-2/*], k:%d""" %dim), "op_load_DBC":nlam.lam_operator("op_load_DBC","rho","phi", "<d/dxk rho || d/dxk phi[boundary=-2/*]>;(L||R)=(*||phi[boundary=-2/*]), k:%d" %dim), } lam_ksps={"solve_laplace_DNBC":nlam.lam_ksp(name="solve_laplace_DNBC", matrix_name="op_laplace_DNBC", ksp_type="gmres", pc_type="ilu", initial_guess_nonzero=True, rtol=get_tol("DNBC.rtol"), atol=get_tol("DNBC.atol"), dtol=get_tol("DNBC.dtol"), maxits=get_tol("DNBC.maxits"), ) } lam_local={"local_dTdt":nlam.lam_local("local_dTdt", field_mwes=["dTdt","Laplace_T","j"], equation=eq_dTdt), "local_set_phi_heating":nlam.lam_local("local_set_phi_heating", aux_args=intensive_params, field_mwes=["phi"], c_code=ccode_heating) } lam_jacobi={"jacobian":nlam.lam_jplan("jacobian","dTdt", ["T","Laplace_T","j"], [[], [# all contributions to d Laplace_T/dT ("operator","op_Laplace_T")], [# all contributions to dj/dT - none in this model. ]], eq_dTdt )} lam_programs={"update_dTdt":nlam.lam_program("update_dTdt", commands=[["TSTART","update_dTdt"], ["GOSUB", "set_Laplace_T"], ["GOSUB", "set_j"], ["SITE-WISE-IPARAMS", "local_dTdt",["v_dTdt","v_Laplace_T","v_j"],[]], # ["DEBUG","v_dTdt","v_dTdt",0], # seems okay! ["TSTOP", "update_dTdt"], ]), "set_Laplace_T":nlam.lam_program("set_Laplace_T", commands=[["TSTART","Laplace_T"], ["SM*V","op_Laplace_T","v_T","v_Laplace_T"], ["CFBOX","Laplace_T","v_Laplace_T"], # ["DEBUG","v_Laplace_T","v_Laplace_T",0], ["TSTOP","Laplace_T"]]), "set_j":nlam.lam_program("set_j", commands=[["TSTART","j"], ["SITE-WISE-IPARAMS","local_set_phi_heating",["v_phi"],[]], ["PULL-FEM","phi","phi[boundary=-2/*]","v_phi","v_phi_boundary"], # ["DEBUG","v_phi_boundary","v_phi_boundary",0], ["SM*V","op_load_DBC","v_phi_boundary","v_rho"], # ["DEBUG","v_rho","v_rho",0], ["SCALE","v_phi",0.0], ["SOLVE","solve_laplace_DNBC","v_rho","v_phi"], ["PUSH-FEM","phi","phi[boundary=-2/*]","v_phi_boundary","v_phi"], # ^ This is to add proper boundary values! ["SM*V","op_j_phi","v_phi","v_j"], # ["DEBUG","v_phi","v_phi",0], # ["DEBUG","v_j","v_j",0], ["CFBOX","j","v_j"], ["TSTOP","j"]]), "execute_jplan":nlam.lam_program("execute_jplan", commands=[["TSTART","execute_jplan"], ["GOSUB", "set_Laplace_T"], ["GOSUB", "set_j"], ["JPLAN","jacobian",["v_T","v_Laplace_T","v_j"]], ["TSTOP","execute_jplan"]]), "rhs":nlam.lam_program("rhs", args_fields=[["arg_dTdt","dTdt"],["arg_T","T"]], # [arg_name,mwe_name] commands=[["TSTART","rhs"], ["DISTRIB","arg_T","v_T"], # ["DEBUG","v_T","v_T",0], ["GOSUB", "update_dTdt"], ["COLLECT","arg_dTdt","v_dTdt"], # ["DEBUG","v_dTdt","v_dTdt",0], ["TSTOP","rhs"] ]), } lam=nlam.make_linalg_machine( name, intensive_params=intensive_params, mwes=lam_mwes.values(), vectors=lam_vectors.values(), operators=lam_operators.values(), ksps=lam_ksps.values(), local_operations=lam_local.values(), jacobi_plans=lam_jacobi.values(), programs=lam_programs.values() ) return (lam,master_mwes_and_fields_by_name)