Skip to content

Simple Induction Heating Application

All the files necessary to reproduce the results can be obtained via downloading this zip file.

Hint

If you are not familiar with coupled magnetic thermal problems, consider visiting our tutorial on Induction Heating first.

Problem and setup description

The problem is really similar to the tutorial Induction Heating but here we focus on applying openCFS in a "real world scenario" by parameterizing the mesh generation, simulation and material xml files and automating evaluations. In general, the setup is depicted in the following figure:

Temperature Dependence

It represents a 3D model of a single-turn coil wrapped around a cylindrical iron core and it is simulated as a quarter model, leveraging symmetry around the rotational axis. The surrounding air domain is chosen to be sufficiently large to prevent boundary conditions at its edges from influencing the simulation results.

The coil is excited by an alternating current, generating a time-varying magnetic field around it. This magnetic field penetrates the conductor inside the coil, in this case, the iron core, inducing eddy currents within the material. These eddy currents circulate through the core, producing heat due to Joule heating.

Before we start with the simulation and material xml definitions, let us have a look at the python script we use to automate the simulations cfsrun.py, which depends on the class and methods defined in pyincludes.py:

from pyincludes import OpenCFS
import matplotlib.pyplot as plt

# %%
################## INPUT BEGIN ##################
# please set the correct working directory for your system
CWD = 'provide correct working directory'
CFS = 'provide path to cfs'
TRELIS = 'provide path to coreform cubit'

# Simulation Parameter
SIM_PARAMETER = {'CURRENT': 100000,
                 'FREQUENCY': 10,
                 'HEAT_TRANSPORT_COEF': 15,
                 'INITIAL_TEMPERATURE': 293.15,
                 'BULK_TEMPERATURE': 293.15,
                 'HEAT_EMISSIVITY': 0.32,
                 'VELOCITY': 0.0,
                 'NUM_CORES': 2,
                 'TIME_STEPS': 5, # delta t
                 'NUM_STEPS': 10}

# Material Parameter
MAT_PARAMETER = {'HEAT_DENSITY_LINEAR': 7850,
                 'HEAT_DENSITY_NONLINEAR': 'heat_density.fnc',
                 'HEAT_CAPACITY_LINEAR': 10,
                 'HEAT_CAPACITY_NONLINEAR': 'heat_capacity.fnc',
                 'HEAT_CONDUCTIVITY_LINEAR': 37.69928,
                 'HEAT_CONDUCTIVITY_NONLINEAR': 'heat_conductivity.fnc',
                 'MAGNETIC_PERMEABILITY_LINEAR': 1.4e-3,
                 'ELECTRIC_CONDUCTIVITY_LINEAR': 4.5e6}

# Evaluation Parameter
EVAL_PARAMETER = {'START_POINT': [0, 0, 0],
                  'END_POINT': [0.0125, 0.1, 0],
                  'NUM_POINTS': 10}

# Input Files
INPUT_FILE = {'TRELIS_TEMPLATE': 'mcl_mesh_template',
              'XML_TEMPLATE': 'harmMag_transT_template',
              'MATERIAL_TEMPLATE': 'mat_template'}

OUTPUT_FILE = {'TRELIS': 'mcl_mesh',
               'XML': 'harmMag_transT',
               'MATERIAL': 'mat'}


cls_openCFS = OpenCFS(CWD, CFS, TRELIS, SIM_PARAMETER, MAT_PARAMETER, EVAL_PARAMETER, INPUT_FILE, OUTPUT_FILE)
global_data, local_data = cls_openCFS.toSimulation()

Most of the parameter settings in cfsrun.py are self explaining. The basic idea is to replace strings like 'HEAT_CONDUCTIVITY_LINEAR' with the actual value in the corresponding template xml file (mat_template.xml and harmMag_transT_template.xml) and mesh file mcl_mesh_template.jou. A neat feature is this section

# Evaluation Parameter
EVAL_PARAMETER = {'START_POINT': [0, 0, 0],
                  'END_POINT': [0.0125, 0.1, 0],
                  'NUM_POINTS': 10}
with which you can evaluate the results (temperature and joule loss density) over a line specified by its start- and endpoint and you can define the number of point along the line. We will see this later on when plotting the results.

Let us have a look at some parts of the <domain> tag in harmMag_transT_template.xml:

  <domain geometryType="3d">
    <variableList>
      <var name="i_coil" value="CURRENT" /> 
      <var name="f_coil" value="FREQUENCY" /> 
      <var name="velocity" value="VELOCITY"/>
      <var name="init_temp" value="INITIAL_TEMPERATURE"/>
      <var name="bulk_temp" value="BULK_TEMPERATURE"/>
      <var name="heatTransportCoef" value="HEAT_TRANSPORT_COEF"/>
      <var name="wire_area" value="0.0006"/>
      <var name="heat_emissivity" value="HEAT_EMISSIVITY"/>
    </variableList>
    ...
When executing cls_openCFS.toSimulation(), the template file is copied and renamed to the actual working filename and the identifier strings are replaced by the actual values.

Defining the problem in openCFS

The solution method we follow here is described in MagHeatPDE as magnetics in frequency-domain - transient heat: linear magnetics - nonlinear heat \rho(T), c_{\textrm p}(T), \lambda(T), \epsilon(T), where \epsilon is the thermal emissivity (only relevant for really high temperatures). This means we can only use constant (no saturation BH curve, no temperature dependency) magnetic permeability, otherwise we would need to switch to a transient magnetics - transient heat setup or use multiharmonic magnetics. So the temperature is just acting on nonlinear parameters in the heat PDE.

Let us now investigate the critical structures of the simulation xml file harmMag_transT_template.xml:

    ...    
  <sequenceStep index="1">
    <analysis>
      <static></static>
    </analysis>

    <pdeList>
      <heatConduction>
        <regionList>
          <region name="V_ROD"/>
        </regionList>

        <bcsAndLoads>
          <temperature name="BC_MT_ROD" value="init_temp" />
          <temperature name="BC_T_ROD" value="init_temp" />
        </bcsAndLoads>
            ...
     </heatConduction>
    </pdeList>
  </sequenceStep>

  <sequenceStep index="2">
    <analysis>
      <harmonic>
        <frequencyList>
          <freq value="f_coil" />
        </frequencyList>
      </harmonic>
    </analysis>

    <pdeList>
      <magneticEdge>
        ...
      </magneticEdge>
    </pdeList>
  </sequenceStep>

  <sequenceStep index="3">
    <analysis>
      <transient>
        <numSteps>NUM_STEPS</numSteps>
        <deltaT>TIME_STEPS</deltaT>
      </transient>
    </analysis>

    <pdeList>
      <heatConduction>
        <regionList>
          <region name="V_ROD" velocityId="vRod" nonLinIds="nonLin_heatCapacity nonLin_heatConductivity nonLin_density nonLin_thermalRadiation"/>      
        </regionList>

        <nonLinList>
          <heatCapacity id="nonLin_heatCapacity"/>
          <heatConductivity id="nonLin_heatConductivity"/>
          <density id="nonLin_density"/>
          <thermalRadiation id="nonLin_thermalRadiation"/>
        </nonLinList>

        <velocityList>
          <velocity name="vRod" coordSysId="cyl1">
            <comp dof="z" value="velocity" />
          </velocity>
        </velocityList>

        <initialValues>
          <initialState>
            <sequenceStep index="1" />
          </initialState>
        </initialValues>

        <bcsAndLoads>
          ...
          <heatSourceDensity volumeRegion="V_ROD" name="V_ROD">
            <sequenceStep index="2">
              <quantity name="magJouleLossPowerDensityOnNodes"
                pdeName="magneticEdge" />
              <timeFreqMapping>
                <constant />
              </timeFreqMapping>
            </sequenceStep>
          </heatSourceDensity>
        </bcsAndLoads>

       ...
      </heatConduction>
    </pdeList>

  </sequenceStep>
</cfsSimulation>

Visualization ParaView

If you are interested in the spatial distribution of Joule losses in the rod, you can open the resultfile harmMag_transT.cfs and open AnalysisStep 2 (harmonic magnetic simulation). You will also discover that the Joule losses result has complex and real part, which might be confusing after reading MagHeatPDE but this is because of implementation reasons and in this case you can ignore the imaginary part and only visualize the real one:

Temperature Dependence

Now these Joule losses are then used in the third sequence step as the right hand side of the heat PDE. If you are interested in the spatial distribution of the temperature, visualize Analysis Step 3 of the result file. But remember, further up, we mentioned a line-plotting feature. For this behalf, we run the last section of `cfsrun.py``

num_time_steps = SIM_PARAMETER['NUM_STEPS']  # e.g., 10
time_steps = list(range(1, num_time_steps + 1))
plt.figure(figsize=(10, 6))
for index, row in local_data.iterrows():
    # Extract temperature values for each timestep
    temperatures = [row[f'Temperature_TimeStep_{t}'] for t in time_steps]
    plt.plot(time_steps, temperatures, marker='o', label=f'Point {index+1}')

plt.xlabel('Time Step')
plt.ylabel('Temperature')
plt.title('Local Data: Temperature Evolution Over Time Steps')
plt.legend(title='Local Points', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.grid(True)
plt.tight_layout()
plt.show()
which plots the time evolution for every point on the evaluation line:

Temperature Dependence