Skip to content

Commit 3582185

Browse files
Add sv0D unit conversion factor and test case
1 parent 44fc5ec commit 3582185

File tree

10 files changed

+204
-9
lines changed

10 files changed

+204
-9
lines changed

Code/Source/solver/ComMod.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,14 @@ void svZeroDSolverInterfaceType::set_data(const svZeroDSolverInterfaceParameters
213213
initial_pressures = params.initial_pressures();
214214
}
215215

216+
// Copy unit conversion factors if provided
217+
if (params.pressure_conversion_factor.defined()) {
218+
pressure_conversion = params.pressure_conversion_factor();
219+
}
220+
if (params.flowrate_conversion_factor.defined()) {
221+
flowrate_conversion = params.flowrate_conversion_factor();
222+
}
223+
216224
has_data = true;
217225
}
218226

Code/Source/solver/ComMod.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,12 @@ class svZeroDSolverInterfaceType
795795
// the svZeroDSolver_interface XML parameter has been defined.
796796
bool has_data = false;
797797

798+
// Unit conversion factors between 3D (svMultiPhysics) and 0D (svZeroD)
799+
// When sending values to 0D, multiply by these; when receiving from 0D,
800+
// divide by these. Defaults are 1.0 (no conversion).
801+
double pressure_conversion = 1.0;
802+
double flowrate_conversion = 1.0;
803+
798804
void set_data(const svZeroDSolverInterfaceParameters& params);
799805
void add_block_face(const std::string& block_name, const std::string& face_name);
800806
};

Code/Source/solver/Parameters.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,10 @@ svZeroDSolverInterfaceParameters::svZeroDSolverInterfaceParameters()
11031103

11041104
set_parameter("Shared_library", "", required, shared_library);
11051105

1106+
// Unit conversion factors (default 1.0 means no scaling).
1107+
set_parameter("Pressure_conversion_factor", 1.0, !required, pressure_conversion_factor);
1108+
set_parameter("Flowrate_conversion_factor", 1.0, !required, flowrate_conversion_factor);
1109+
11061110
};
11071111

11081112
void svZeroDSolverInterfaceParameters::set_values(tinyxml2::XMLElement* xml_elem)

Code/Source/solver/Parameters.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,13 @@ class svZeroDSolverInterfaceParameters : public ParameterLists
671671

672672
Parameter<std::string> shared_library;
673673

674+
// Unit conversion factors between 3D and 0D models
675+
// Pressure and flowrate values will be multiplied by these factors before
676+
// being sent to the 0D model, and the inverse factors will be applied to
677+
// 0D outputs before returning to 3D.
678+
Parameter<double> pressure_conversion_factor;
679+
Parameter<double> flowrate_conversion_factor;
680+
674681
bool value_set = false;
675682
};
676683

Code/Source/solver/svZeroD_subroutines.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,13 @@ void init_svZeroD(ComMod& com_mod, const CmMod& cm_mod)
352352
interface->return_ydot(last_state_ydot);
353353
for (int s = 0; s < numCoupledSrfs; ++s) {
354354
if (init_flow_flag == 1) {
355-
lpn_state_y[sol_IDs[2 * s]] = init_flow;
355+
// Apply flowrate conversion when initializing state
356+
lpn_state_y[sol_IDs[2 * s]] = init_flow * solver_interface.flowrate_conversion;
356357
cplBC.fa[s].y = lpn_state_y[sol_IDs[2 * s]];
357358
}
358359
if (init_press_flag == 1) {
359-
lpn_state_y[sol_IDs[2 * s + 1]] = init_press;
360+
// Apply pressure conversion when initializing state
361+
lpn_state_y[sol_IDs[2 * s + 1]] = init_press * solver_interface.pressure_conversion;
360362
cplBC.fa[s].y = lpn_state_y[sol_IDs[2 * s + 1]];
361363
}
362364
}
@@ -434,14 +436,14 @@ void calc_svZeroD(ComMod& com_mod, const CmMod& cm_mod, char BCFlag) {
434436

435437
total_flow = 0.0;
436438

437-
// Update pressure and flow in the zeroD model
439+
// Update pressure and flow in the zeroD model (apply unit conversions)
438440
for (int i = 0; i < numCoupledSrfs; ++i) {
439441
if (i < nDir) {
440-
params[0] = PCoupled[i];
441-
params[1] = PnCoupled[i];
442+
params[0] = PCoupled[i] * cplBC.svzerod_solver_interface.pressure_conversion;
443+
params[1] = PnCoupled[i] * cplBC.svzerod_solver_interface.pressure_conversion;
442444
} else {
443-
params[0] = in_out_sign[i] * QCoupled[i];
444-
params[1] = in_out_sign[i] * QnCoupled[i];
445+
params[0] = in_out_sign[i] * QCoupled[i] * cplBC.svzerod_solver_interface.flowrate_conversion;
446+
params[1] = in_out_sign[i] * QnCoupled[i] * cplBC.svzerod_solver_interface.flowrate_conversion;
445447
total_flow += QCoupled[i];
446448
}
447449
update_svZeroD_block_params(svzd_blk_names[i], times, params);
@@ -455,10 +457,12 @@ void calc_svZeroD(ComMod& com_mod, const CmMod& cm_mod, char BCFlag) {
455457

456458
for (int i = 0; i < numCoupledSrfs; ++i) {
457459
if (i < nDir) {
458-
QCoupled[i] = in_out_sign[i] * lpn_state_y[sol_IDs[2 * i]];
460+
// Convert 0D flow back to 3D units
461+
QCoupled[i] = (in_out_sign[i] * lpn_state_y[sol_IDs[2 * i]]) / cplBC.svzerod_solver_interface.flowrate_conversion;
459462
cplBC.fa[i].y = QCoupled[i];
460463
} else {
461-
PCoupled[i] = lpn_state_y[sol_IDs[2 * i + 1]];
464+
// Convert 0D pressure back to 3D units
465+
PCoupled[i] = lpn_state_y[sol_IDs[2 * i + 1]] / cplBC.svzerod_solver_interface.pressure_conversion;
462466
cplBC.fa[i].y = PCoupled[i];
463467
}
464468
}

tests/cases/fluid/pipe_RCR_sv0D/svzerod_3Dcoupling.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"bc_name": "RCR",
1111
"bc_type": "RCR",
1212
"bc_values": {
13+
"_comment": "cgs units. R: (dyn/cm^2).s/cm^3, C: cm^3/(dyn/cm^2), Pd: (dyn/cm^2)",
1314
"Rp": 121.0,
1415
"Rd": 1212.0,
1516
"C": 1.5e-4,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# pipe_RCR_sv0D_units
2+
3+
This test is identical to `fluid/pipe_RCR_sv0D` but uses mixed units:
4+
5+
- solver.xml: cgs units (dynes/cm^2, cm^3/s)
6+
- svZeroD JSON: clinical units (mmHg, mL/s)
7+
8+
The `svZeroDSolver_interface` specifies conversion factors so that values are converted automatically:
9+
10+
- `Pressure_conversion_factor = 0.00075006157584566` (dynes/cm^2 -> mmHg)
11+
- `Flowrate_conversion_factor = 1.0` (cm^3/s -> mL/s)
12+
13+
Mesh and inflow files are referenced from the original test directory `pipe_RCR_sv0D/` to avoid duplication.
14+
Also, the reference result `result_002.vtu` in `pipe_RCR_sv0D/` is used for comparison
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<svMultiPhysicsFile version="0.1">
3+
4+
<GeneralSimulationParameters>
5+
6+
<Continue_previous_simulation> false </Continue_previous_simulation>
7+
<Number_of_spatial_dimensions> 3 </Number_of_spatial_dimensions>
8+
<Number_of_time_steps> 2 </Number_of_time_steps>
9+
<Time_step_size> 0.005 </Time_step_size>
10+
<Spectral_radius_of_infinite_time_step> 0.50 </Spectral_radius_of_infinite_time_step>
11+
<Searched_file_name_to_trigger_stop> STOP_SIM </Searched_file_name_to_trigger_stop>
12+
13+
<Save_results_to_VTK_format> 1 </Save_results_to_VTK_format>
14+
<Name_prefix_of_saved_VTK_files> result </Name_prefix_of_saved_VTK_files>
15+
<Increment_in_saving_VTK_files> 1 </Increment_in_saving_VTK_files>
16+
<Start_saving_after_time_step> 1 </Start_saving_after_time_step>
17+
18+
<Increment_in_saving_restart_files> 200 </Increment_in_saving_restart_files>
19+
<Convert_BIN_to_VTK_format> 0 </Convert_BIN_to_VTK_format>
20+
21+
<Verbose> 1 </Verbose>
22+
<Warning> 0 </Warning>
23+
<Debug> 0 </Debug>
24+
25+
</GeneralSimulationParameters>
26+
27+
<Add_mesh name="msh" >
28+
29+
<Mesh_file_path> ../pipe_RCR_sv0D/mesh-complete/mesh-complete.mesh.vtu </Mesh_file_path>
30+
31+
<Add_face name="lumen_inlet">
32+
<Face_file_path> ../pipe_RCR_sv0D/mesh-complete/mesh-surfaces/lumen_inlet.vtp </Face_file_path>
33+
</Add_face>
34+
35+
<Add_face name="lumen_outlet">
36+
<Face_file_path> ../pipe_RCR_sv0D/mesh-complete/mesh-surfaces/lumen_outlet.vtp </Face_file_path>
37+
</Add_face>
38+
39+
<Add_face name="lumen_wall">
40+
<Face_file_path> ../pipe_RCR_sv0D/mesh-complete/mesh-surfaces/lumen_wall.vtp </Face_file_path>
41+
</Add_face>
42+
43+
</Add_mesh>
44+
45+
<Add_equation type="fluid" >
46+
<Coupled> 1 </Coupled>
47+
<Min_iterations> 3 </Min_iterations>
48+
<Max_iterations> 10 </Max_iterations>
49+
<Tolerance> 1e-3 </Tolerance>
50+
<Backflow_stabilization_coefficient> 0.2 </Backflow_stabilization_coefficient>
51+
52+
<Density> 1.06 </Density> <!-- g/cm^3 -->
53+
<Viscosity model="Constant" >
54+
<Value> 0.04 </Value> <!-- poise -->
55+
</Viscosity>
56+
57+
<Output type="Spatial" >
58+
<Velocity> true </Velocity>
59+
<Pressure> true </Pressure>
60+
<Traction> true </Traction>
61+
<WSS> true </WSS>
62+
<Vorticity> true </Vorticity>
63+
<Divergence> true </Divergence>
64+
</Output>
65+
66+
<LS type="NS" >
67+
<Linear_algebra type="fsils" >
68+
<Preconditioner> fsils </Preconditioner>
69+
</Linear_algebra>
70+
<Max_iterations> 10 </Max_iterations>
71+
<NS_GM_max_iterations> 3 </NS_GM_max_iterations>
72+
<NS_CG_max_iterations> 500 </NS_CG_max_iterations>
73+
<Tolerance> 1e-3 </Tolerance>
74+
<NS_GM_tolerance> 1e-3 </NS_GM_tolerance>
75+
<NS_CG_tolerance> 1e-3 </NS_CG_tolerance>
76+
<Krylov_space_dimension> 50 </Krylov_space_dimension>
77+
</LS>
78+
79+
<svZeroDSolver_interface>
80+
<Coupling_type> semi-implicit </Coupling_type>
81+
<Configuration_file> svzerod_3Dcoupling.json </Configuration_file>
82+
<Shared_library> ../../../../svZeroDSolver/build/src/interface/libsvzero_interface.dylib </Shared_library>
83+
<Initial_flows> 0.0 </Initial_flows>
84+
<Initial_pressures> 0.0 </Initial_pressures>
85+
<Pressure_conversion_factor> 0.00075006157584566 </Pressure_conversion_factor> <!-- dyn/cm^2 to mmHg -->
86+
<Flowrate_conversion_factor> 1.0 </Flowrate_conversion_factor> <!-- cm^3/s to ml/s -->
87+
</svZeroDSolver_interface>
88+
89+
<Add_BC name="lumen_inlet" >
90+
<Type> Dir </Type>
91+
<Time_dependence> Unsteady </Time_dependence>
92+
<Temporal_values_file_path> ../pipe_RCR_sv0D/lumen_inlet.flw</Temporal_values_file_path>
93+
<Zero_out_perimeter> true </Zero_out_perimeter>
94+
<Impose_flux> true </Impose_flux>
95+
</Add_BC>
96+
97+
<Add_BC name="lumen_outlet" >
98+
<Type> Neu </Type>
99+
<Time_dependence> Coupled </Time_dependence>
100+
<svZeroDSolver_block> RCR_coupling </svZeroDSolver_block>
101+
</Add_BC>
102+
103+
<Add_BC name="lumen_wall" >
104+
<Type> Dir </Type>
105+
<Time_dependence> Steady </Time_dependence>
106+
<Value> 0.0 </Value>
107+
</Add_BC>
108+
109+
</Add_equation>
110+
111+
</svMultiPhysicsFile>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"simulation_parameters": {
3+
"coupled_simulation": true,
4+
"number_of_time_pts": 100,
5+
"output_all_cycles": true,
6+
"steady_initial": false
7+
},
8+
"boundary_conditions": [
9+
{
10+
"bc_name": "RCR",
11+
"bc_type": "RCR",
12+
"bc_values": {
13+
"_comment": "Clinical units. R: mmHg.s/mL, C: mL/mmHg, Pd: mmHg",
14+
"Rp": 0.09075745067,
15+
"Rd": 0.90907462992,
16+
"C": 0.19998358112,
17+
"Pd": 0.0
18+
}
19+
}
20+
],
21+
"external_solver_coupling_blocks": [
22+
{
23+
"name": "RCR_coupling",
24+
"type": "FLOW",
25+
"location": "inlet",
26+
"connected_block": "RCR",
27+
"periodic": false,
28+
"values": {
29+
"t": [0.0, 1.0],
30+
"Q": [1.0, 1.0]
31+
}
32+
}
33+
],
34+
"junctions": [],
35+
"vessels": []
36+
}

tests/test_fluid.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ def test_pipe_RCR_sv0D(n_proc):
6464
t_max = 2
6565
run_with_reference(base_folder, test_folder, fields, n_proc, t_max)
6666

67+
def test_pipe_RCR_sv0D_different_units(n_proc):
68+
test_folder = "pipe_RCR_sv0D_different_units"
69+
t_max = 2
70+
run_with_reference(base_folder, test_folder, fields, n_proc, t_max, name_ref="../pipe_RCR_sv0D/result_002.vtu")
6771

6872
def test_driven_cavity_2d(n_proc):
6973
test_folder = "driven_cavity_2d"

0 commit comments

Comments
 (0)