Skip to content

Commit 5ce3d76

Browse files
committed
creat scripts/ folder, move parallel calculation folder to scripts, rename markdown as README.md
1 parent da9278b commit 5ce3d76

3 files changed

Lines changed: 165 additions & 9 deletions

File tree

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# Running a parameter grid across parallel Ansys sessions
22

3-
This documents the pattern originally in `machine_design/parallel_calculation/`
4-
(`runner_parallel.py` , `calculate_combination.py`, added by Jan Laksar), kept
5-
here after that folder was removed in issue #21.
3+
This is the parallel Ansys computation pattern originally in
4+
`machine_design/parallel_calculation/` (added by Jan Laksar), moved here in
5+
issue #21 along with the two scripts (`runner_parallel.py`,
6+
`calculate_combination.py`). The large `SynRM_orig.aedt` example project was
7+
dropped since it does not belong in git. Running these scripts requires your
8+
own base `.aedt` project.
69

710
## Problem
811

@@ -15,8 +18,8 @@ roughly by the number of workers.
1518
## Method
1619

1720
1. Split the full grid of tasks into `N_WORKERS` contiguous chunks.
18-
2. For each worker, copy the base `.aedt` project file to its own file before
19-
opening it. Ansys locks a project file while it is open, so every worker
21+
2. For each worker, copy the base `.aedt` project file to its own file before
22+
opening it. Ansys locks a project file while it is open, so every worker
2023
needs its own copy rather than sharing one file.
2124
3. Start `multiprocessing.Pool(N_WORKERS)` and run one worker function per
2225
chunk. Each worker opens its own `Desktop(non_graphical=True,
@@ -36,7 +39,7 @@ roughly by the number of workers.
3639

3740
## Example
3841

39-
The removed `runner_parallel.py` swept a 16x16 grid of `Id`/`Iq` values (0.0
40-
to 3.2 A in 0.2 A steps) and recorded flux linkages, inductances, and torque
41-
for each point, with `calculate_combination.py` doing the per-point solve
42-
and extraction described above.
42+
`runner_parallel.py` swept a 16x16 grid of `Id`/`Iq` values (0.0 to 3.2 A
43+
in 0.2 A steps) and recorded flux linkages, inductances, and torque for
44+
each point, with `calculate_combination.py` doing the per-point solve and
45+
extraction described above.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import numpy as np
2+
3+
4+
def main(m2d, task_chunk, setup_name):
5+
6+
def run_simulation(Id, Iq):
7+
m2d.variable_manager["Id"] = f"{Id}A"
8+
m2d.variable_manager["Iq"] = f"{Iq}A"
9+
10+
m2d.save_project()
11+
m2d.analyze_setup(setup_name, use_auto_settings=False, cores=1, tasks=1)
12+
13+
expressions = ["I_d1", "I_q1", "Flux_d1", "Flux_q1", "Flux_e_d1", "Flux_e_q1", "Ld1", "Lq1", "Ld1q1", "Lq1d1", "Moving1.Torque"]
14+
15+
sols = m2d.post.get_solution_data(expressions=expressions, primary_sweep_variable="Time")
16+
17+
out = np.zeros(len(expressions))
18+
19+
for i, expr in enumerate(expressions):
20+
data = sols.data_real(expr)[:-1]
21+
val = float(np.mean(data))
22+
23+
if expr.startswith("L"):
24+
val /= 1e9
25+
26+
out[i] = val
27+
28+
return out
29+
30+
# --- chunk processing ---
31+
results_local = []
32+
total = len(task_chunk)
33+
for k, (Id, Iq, i, j) in enumerate(task_chunk, start=1):
34+
print(f"[INFO] {k}/{total} | Id={Id:.3f} A | Iq={Iq:.3f} A")
35+
36+
res = run_simulation(Id, Iq)
37+
38+
results_local.append((i, j, res))
39+
40+
return results_local
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import os
2+
import shutil
3+
import time
4+
from multiprocessing import Pool
5+
6+
import calculate_combination
7+
import h5py
8+
import numpy as np
9+
from ansys.aedt.core import Desktop, Maxwell2d
10+
11+
from machine_design.config import load_config
12+
13+
# =========================================================
14+
# CONFIGURATION
15+
# =========================================================
16+
config = load_config()
17+
AEDT_VERSION = config["aedt_version"]
18+
19+
PROJECT_DIR = os.path.join(os.getcwd(), config["project_dir"])
20+
BASE_PROJECT = "SynRM_orig"
21+
DESIGN_NAME = "Design02_def_Idq"
22+
SETUP_NAME = "Setup1"
23+
24+
N_WORKERS = config["n_workers"] # less then number of logical processors
25+
26+
27+
# =========================================================
28+
# PROJECT COPY
29+
# =========================================================
30+
def copy_project(worker_id):
31+
src = os.path.join(PROJECT_DIR, BASE_PROJECT + ".aedt")
32+
dst_name = f"SynRM_worker_{worker_id}.aedt"
33+
dst = os.path.join(PROJECT_DIR, dst_name)
34+
35+
shutil.copyfile(src, dst)
36+
37+
return dst_name
38+
39+
40+
# =========================================================
41+
# WORKER
42+
# =========================================================
43+
def worker(args):
44+
45+
worker_id, task_chunk = args
46+
47+
project_name = copy_project(worker_id)
48+
49+
desktop = Desktop(specified_version=AEDT_VERSION, non_graphical=True, new_desktop=True, close_on_exit=False)
50+
51+
app = Maxwell2d(project=project_name, design=DESIGN_NAME)
52+
53+
results = calculate_combination.main(app, task_chunk, SETUP_NAME)
54+
55+
desktop.release_desktop(close_projects=True, close_on_exit=False)
56+
57+
return results
58+
59+
60+
# =========================================================
61+
# MAIN
62+
# =========================================================
63+
def run():
64+
65+
Id_vec = np.arange(0.0, 3.2, 0.2) # 16 values
66+
Iq_vec = np.arange(0.0, 3.2, 0.2) # 16 values
67+
68+
tasks = []
69+
for i, Id in enumerate(Id_vec):
70+
for j, Iq in enumerate(Iq_vec):
71+
tasks.append((Id, Iq, i, j))
72+
73+
chunk_size = int(np.ceil(len(tasks) / N_WORKERS))
74+
chunks = [tasks[i : i + chunk_size] for i in range(0, len(tasks), chunk_size)]
75+
76+
args = [(i, chunk) for i, chunk in enumerate(chunks)]
77+
78+
results = np.zeros((len(Id_vec), len(Iq_vec), 11))
79+
80+
with Pool(N_WORKERS) as pool:
81+
outputs = pool.map(worker, args)
82+
83+
rows = []
84+
for chunk in outputs:
85+
for i, j, res in chunk:
86+
results[i, j, :] = res
87+
rows.append(list(results[i, j, :]))
88+
data_out = np.array(rows)
89+
90+
header = "Id,Iq,Flux_d,Flux_q,Flux_e_d,Flux_e_q,L_d,L_q,L_dq,L_qd,Torque"
91+
np.savetxt("results_grid.csv", data_out, delimiter=",", header=header, comments="")
92+
93+
with h5py.File("results_grid.h5", "w") as f:
94+
f.create_dataset("Id", data=Id_vec)
95+
f.create_dataset("Iq", data=Iq_vec)
96+
f.create_dataset("results", data=results)
97+
98+
print("[INFO] DONE")
99+
100+
return results
101+
102+
103+
# =========================================================
104+
# ENTRY POINT
105+
# =========================================================
106+
if __name__ == "__main__":
107+
start = time.perf_counter()
108+
109+
run()
110+
111+
end = time.perf_counter()
112+
113+
print(f"Time of calculation: {end - start:.6f} s")

0 commit comments

Comments
 (0)