// module: TRUE
/* This script is run in PRIMER to create a ptf file containing the head excursion zone bands in car model space.
*
* It is run from the D3PLOT script d3plot_automotive_assessment.mjs using the System() function to start PRIMER,
* read in the appropriate keyword file and pass the required variables to the script with -js_arg= command line
* arguments which can be read from the global <arguments> array in this script.
*
* They are defined in the following order:
*
* 1. The cut section thickness
* 2. The cut section node
* 3. The first shift deform node
* 4. The second shift deform node
* 5. The third shift deform value
* 6. The seat centre y coordinate
* 7. The intrusion from the seat centre y coordinate
* 8. The vehicle direction
* 9. Unit system (Workflow.UNIT_SYSTEM_U1, etc..)
*
* If the order changes in the D3PLOT script, this script must be updated to match.
*/
import { JSPath } from "../../modules/shared/path.mjs";
import { WorkflowUnits } from "../../../modules/units.mjs";
// @ts-ignore
create_zones_ptf(arguments);
/**
* Creates the head excursion zone bands as null shell parts in car model space
* and writes them to a ptf file.
* @param {string[]} args Arguments passed to this script from the D3PLOT script
*/
function create_zones_ptf(args) {
let m_first = Model.First();
/* Get the arguments passed to the script */
let cut_section_thickness = Number.parseFloat(args[1]);
let cut_section_node_1 = Node.GetFromID(m_first, Number.parseInt(args[2]));
let shift_deformed_node_1 = Node.GetFromID(m_first, Number.parseInt(args[3]));
let shift_deformed_node_2 = Node.GetFromID(m_first, Number.parseInt(args[4]));
let shift_deformed_node_3 = Node.GetFromID(m_first, Number.parseInt(args[5]));
let seat_centre_y = Number.parseFloat(args[6]);
let intrusion_from_seat_centre_y = Number.parseFloat(args[7]);
let vehicle_direction = args[8];
let unit_system = Number.parseInt(args[9]);
/* Set the workflows directory - whilst this is a PRIMER script, it is saved
* in the scripts/automotive_assessments/post/primer folder hence passing
* JSPath.POST to set the workflow directory */
JSPath.SetWorkflowsDirectory(JSPath.POST);
/*
---> X Car pointing in -ve X
=============================
LHD CAR RHD CAR
near seat (passenger Y) > 0 near seat (passenger Y) < 0
+ -
(O) barrier
|
v
Y /--OOOO---------OOOO---] Y /--OOOO---------OOOO---]
^ /< [Near] [ ] | ^ /< [Driver] [ ] |
| | | | | |
| | | | | |
| \< [Driver] [ ] | | \< [Near] [ ] |
\--OOOO---------OOOO---] \--OOOO---------OOOO---]
^
|
(O) barrier
<--- X Car pointing in +VE X
=============================
LHD CAR RHD CAR
near seat (passenger Y) > 0 near seat (passenger Y) < 0
- +
(O) barrier
|
v
/--OOOO---------OOOO---] /--OOOO---------OOOO---]
| /< [Near] [ ] | | /< [Driver] [ ] |
| | | | | |
| | | | | |
V \< [Driver] [ ] | V \< [Near] [ ] |
Y \--OOOO---------OOOO---] Y \--OOOO---------OOOO---]
^
|
(O) barrier
*/
let y_excursion = 0.0; /* Start of red zone */
if (seat_centre_y > 0) {
/* Note the car is assumed to point in the -ve x direction
* "right" means from the perspective of the analyst looking at the front of the vehicle (this is "left side for the occupants")
*
* if the passenger seat (struck side seat a.k.a near seat) y coordinate is +ve
* then the car is assumed to be struck from the vehicle right and intrusion is right to left (in the -ve y direction)
* so to get intrusion_y coordinate add intrusion_from_seat_center_y to seat_y */
y_excursion = seat_centre_y + intrusion_from_seat_centre_y;
} else {
/* Intrusion is from left to right when looking at the front of the vehicle (i.e. in the +ve y direction) */
y_excursion = seat_centre_y - intrusion_from_seat_centre_y;
}
let output_dir = `${JSPath.GetWorkflowsDirectory()}scripts/automotive_assessments/post/primer/output`;
let ptf_file = `${output_dir}/zones.ptf`;
if (File.Exists(ptf_file)) {
Message(`${ptf_file} exists so deleting old ptfs before creating new ptf`);
File.Delete(ptf_file);
if (File.Exists(`${ptf_file}01`)) File.Delete(`${ptf_file}01`);
}
/* Height (assume -1m to +2m is suitable) */
var z_bot = -1 * WorkflowUnits.LengthToMetresFactor(unit_system);
var z_top = 2 * WorkflowUnits.LengthToMetresFactor(unit_system);
if (cut_section_thickness == 0)
cut_section_thickness = 10 * WorkflowUnits.LengthToMillimetresFactor(unit_system); /* Nominal 10mm thick */
let thick_cut = cut_section_thickness;
let xsign = 1;
if (/pos/i.test(vehicle_direction)) xsign = -1;
let x =
cut_section_node_1.x +
(xsign * thick_cut * 0.99) / 2; /* issue with cut section if shells lie exactly on cut-section x hence '-1' */
let y = seat_centre_y;
/* Multiply by sign for the case when the car is struck from the left hand side */
let sign = 1;
if (y_excursion < 0) sign = -1;
let y_red_orange = y;
let y_orange_yellow = y - 0.125 * WorkflowUnits.LengthToMetresFactor(unit_system) * sign;
let y_yellow_green = y - 0.25 * WorkflowUnits.LengthToMetresFactor(unit_system) * sign;
let width = 10 * WorkflowUnits.LengthToMetresFactor(unit_system) * sign;
let bool_red = true;
let bool_orange = true;
let bool_yellow = true;
if (Math.abs(y_excursion) <= Math.abs(y_yellow_green)) {
/* No red, orange and yellow. Green starts at y_excursion */
y_yellow_green = y_excursion;
bool_red = false;
bool_orange = false;
bool_yellow = false;
} else if (Math.abs(y_excursion) <= Math.abs(y_orange_yellow)) {
/* No red and orange. Yellow starts at y_excursion */
y_orange_yellow = y_excursion;
bool_red = false;
bool_orange = false;
} else if (Math.abs(y_excursion) <= Math.abs(y_red_orange)) {
/* No red. Orange starts at y_excursion */
y_red_orange = y_excursion;
bool_red = false;
}
/* Assume struck far side is at +ve y and driver/occupant is sat at -ve y such that they move in +ve y direcion
/* Model to create null shells in */
Message("Making new model...");
let m = new Model();
/* Make dummy material */
let mat = new Material(m, 1, "NULL");
mat.SetPropertyByName("RO", WorkflowUnits.MassToKilogramsFactor(unit_system));
/* Make dummy section */
let section = new Section(m, 1, Section.SHELL, "NULL_SHELL");
/* Set section thickness to 1mm */
section.t1 = 0.001 * WorkflowUnits.LengthToMetresFactor(unit_system);
section.t2 = 0.001 * WorkflowUnits.LengthToMetresFactor(unit_system);
section.t3 = 0.001 * WorkflowUnits.LengthToMetresFactor(unit_system);
section.t4 = 0.001 * WorkflowUnits.LengthToMetresFactor(unit_system);
/* Make parts */
let parts_list = [1, 5, 6, 7, 8]; /* Used in D3PLOT excursion plot to control which parts are visible */
let shift_deformed_pid = 1;
let red_zone_pid = 2;
let orange_zone_pid = 3;
let yellow_zone_pid = 4;
let green_zone_pid = 5;
let blue_centre_line_pid = 6;
let capping_zone_pid = 7;
let white_zone_pid = 8;
new Part(m, shift_deformed_pid, 1, 1, "Shift Deformed");
if (bool_red) {
new Part(m, red_zone_pid, 1, 1, "RED ZONE");
parts_list.push(2);
}
if (bool_orange) {
new Part(m, orange_zone_pid, 1, 1, "ORANGE ZONE");
parts_list.push(3);
}
if (bool_yellow) {
new Part(m, yellow_zone_pid, 1, 1, "YELLOW ZONE");
parts_list.push(4);
}
new Part(m, green_zone_pid, 1, 1, "GREEN ZONE");
new Part(m, blue_centre_line_pid, 1, 1, "BLUE CENTER-LINE");
new Part(m, capping_zone_pid, 1, 1, "GREY CAPPING ZONE");
new Part(m, white_zone_pid, 1, 1, "WHITE ZONE"); /* Used for consistent image scaling */
/* Make nodes */
let sdn1 = copy_node_to_new_model_return_nid(shift_deformed_node_1, m);
let sdn2 = copy_node_to_new_model_return_nid(shift_deformed_node_2, m);
let sdn3 = copy_node_to_new_model_return_nid(shift_deformed_node_3, m);
let csn4 = copy_node_to_new_model_return_nid(cut_section_node_1, m);
/* shell nodes */
/* RED/ORANGE ZONE (seat centreline) */
new Node(m, 1, x, y_red_orange, z_bot);
new Node(m, 2, x, y_red_orange, z_top);
/* RED/CAPPING ZONE (excursion taken from previous side impact analysis)
* note if y_excursion < y then orange starts at y_excursion
* if y_excursion < y -125 then no orange and yellow starts at y_excursion
* if y_excursion < y -255 then no yellow and green starts at y_excursion */
new Node(m, 3, x, y_excursion, z_top);
new Node(m, 4, x, y_excursion, z_bot);
/* ORANGE/YELLOW ZONE */
new Node(m, 5, x, y_orange_yellow, z_bot);
new Node(m, 6, x, y_orange_yellow, z_top);
/* YELLOW/GREEN ZONE */
new Node(m, 7, x, y_yellow_green, z_bot);
new Node(m, 8, x, y_yellow_green, z_top);
/* GREEN ZONE (arbitrarily chosen to end at far seat centreline (assumed to be -y)) */
new Node(m, 9, x, -y, z_bot);
new Node(m, 10, x, -y, z_top);
/* BLUE CENTERLINE (10mm wide) */
let blue_line_width = 0.01 * WorkflowUnits.LengthToMetresFactor(unit_system);
let x_blue_line =
x -
0.002 *
WorkflowUnits.LengthToMetresFactor(
unit_system
); /* Offset blue line forewards by 2mm so that it is more visible */
new Node(m, 11, x_blue_line, -blue_line_width / 2, z_bot);
new Node(m, 12, x_blue_line, -blue_line_width / 2, z_top);
new Node(m, 13, x_blue_line, blue_line_width / 2, z_top);
new Node(m, 14, x_blue_line, blue_line_width / 2, z_bot);
/* Capping Zone (10m wide) grey part */
new Node(m, 15, x, width / 2, z_bot);
new Node(m, 16, x, width / 2, z_top);
/* Right border (white part) //used for consistent zoom/scale */
new Node(m, 17, x, -width / 2, z_bot);
new Node(m, 18, x, -width / 2, z_top);
/* Make shells */
new Shell(m, 1, shift_deformed_pid, sdn1, sdn2, csn4, csn4);
new Shell(m, 2, shift_deformed_pid, sdn1, sdn3, csn4, csn4);
new Shell(m, 3, shift_deformed_pid, sdn2, sdn3, csn4, csn4);
new Shell(m, 4, shift_deformed_pid, sdn1, sdn2, sdn3, sdn3);
if (bool_red) new Shell(m, 5, red_zone_pid, 1, 2, 3, 4);
if (bool_orange) new Shell(m, 6, orange_zone_pid, 1, 5, 6, 2);
if (bool_yellow) new Shell(m, 7, yellow_zone_pid, 5, 7, 8, 6);
new Shell(m, 8, green_zone_pid, 7, 9, 10, 8);
new Shell(m, 9, blue_centre_line_pid, 11, 12, 13, 14);
new Shell(m, 10, capping_zone_pid, 3, 4, 15, 16);
new Shell(m, 11, white_zone_pid, 9, 10, 18, 17);
m_first.Delete();
//write out pft file using temp macro
let write_ptf_macro_file = File.Mktemp();
let macro =
`Window("Tools/Keywords").Button("Model Tab")
Window("Model functions").Button("Write")
In Window("WRITE TO FILE")
.Radio("Filetype Radio") = "PTF / d3plot"
.Textbox("File:") = "` +
ptf_file +
'"\n' +
` .Button("Apply")
End In
`;
Message("Writing macro to " + write_ptf_macro_file);
let f = new File(write_ptf_macro_file, File.WRITE);
f.Write(macro);
f.Close();
Message("Running macro " + write_ptf_macro_file);
PlayMacro(write_ptf_macro_file);
Message("Finish macro " + write_ptf_macro_file);
File.Delete(write_ptf_macro_file);
Message("Exiting primer after successfully writing excursion zones to " + ptf_file);
}
/**
* Copies a node to a new model and returns the new node id
* @param {Node} n Node to copy
* @param {Model} m model to copy node to
* @returns {number}
*/
function copy_node_to_new_model_return_nid(n, m) {
let new_node = new Node(m, n.nid, n.x, n.y, n.z);
return new_node.nid;
}