Class DexpiXmlWriter

java.lang.Object
neqsim.process.processmodel.dexpi.DexpiXmlWriter

public final class DexpiXmlWriter extends Object
Utility for exporting ProcessSystems created from DEXPI data back into a lightweight DEXPI XML representation.

The writer groups all discovered DexpiStream segments by line number (or fluid code when a line is not available) to generate simple <PipingNetworkSystem> elements with associated <PipingNetworkSegment> children.

Version:
1.0
Author:
NeqSim
See Also:
  • Field Details

  • Constructor Details

    • DexpiXmlWriter

      private DexpiXmlWriter()
  • Method Details

    • roundTrip

      public static void roundTrip(File inputFile, File outputFile, Stream templateStream) throws IOException, DexpiXmlReaderException
      Performs a bi-directional DEXPI round-trip: reads an existing DEXPI XML P&ID, creates a NeqSim process model from it using the provided fluid template, runs the simulation, and writes the enriched results back to DEXPI XML.

      This enables a "digital twin" workflow where P&ID designs are imported, simulated with rigorous thermodynamics, and exported back with updated process data (temperatures, pressures, flow rates, compositions).

      Parameters:
      inputFile - the source DEXPI XML file to read
      outputFile - the destination file for the enriched DEXPI XML
      templateStream - the template stream providing fluid composition for simulation
      Throws:
      IOException - if reading or writing fails
      DexpiXmlReaderException - if the DEXPI XML cannot be parsed
    • write

      public static void write(ProcessSystem processSystem, File file) throws IOException
      Writes the provided ProcessSystem to a DEXPI XML file.
      Parameters:
      processSystem - process model to export
      file - output file
      Throws:
      IOException - if writing fails
    • write

      public static void write(ProcessSystem processSystem, File file, Map<String, MeasurementDeviceInterface> transmitters, Map<String, ControllerDeviceInterface> controllers) throws IOException
      Writes the provided ProcessSystem to a DEXPI XML file, including instrument and controller data when provided.
      Parameters:
      processSystem - process model to export
      file - output file
      transmitters - map of tag name to transmitter (may be null)
      controllers - map of tag name to controller (may be null)
      Throws:
      IOException - if writing fails
    • write

      public static void write(ProcessSystem processSystem, OutputStream outputStream) throws IOException
      Writes the provided ProcessSystem to a DEXPI XML stream.
      Parameters:
      processSystem - process model to export
      outputStream - destination stream
      Throws:
      IOException - if writing fails
    • write

      public static void write(ProcessSystem processSystem, OutputStream outputStream, Map<String, MeasurementDeviceInterface> transmitters, Map<String, ControllerDeviceInterface> controllers) throws IOException
      Writes the provided ProcessSystem to a DEXPI XML stream, including instrument and controller data when provided.
      Parameters:
      processSystem - process model to export
      outputStream - destination stream
      transmitters - map of tag name to transmitter (may be null)
      controllers - map of tag name to controller (may be null)
      Throws:
      IOException - if writing fails
    • createDocument

      private static Document createDocument() throws IOException
      Throws:
      IOException
    • createPlantInformation

      private static Element createPlantInformation(Document document)
    • appendProcessUnit

      private static void appendProcessUnit(Document document, Element parent, DexpiProcessUnit processUnit, Set<String> usedIds, String inletNozzleId, List<String> outletNozzleIds, DexpiLayoutEngine.EquipmentPosition position, int labelIndex, Map<String,double[]> nozzlePositions)
    • appendNativeEquipment

      private static void appendNativeEquipment(Document document, Element parent, ProcessEquipmentInterface unit, Set<String> usedIds, String inletNozzleId, List<String> outletNozzleIds, DexpiLayoutEngine.EquipmentPosition position, int labelIndex, Map<String,double[]> nozzlePositions)
      Appends a native NeqSim equipment (non-DEXPI-origin) to the document using reverse mapping.
      Parameters:
      document - the XML document
      parent - the parent element
      unit - the process equipment
      usedIds - set of used IDs
      inletNozzleId - the inlet nozzle ID to create
      outletNozzleIds - the outlet nozzle IDs to create
      position - the computed layout position (may be null)
      labelIndex - label counter for unique IDs
      nozzlePositions - map of nozzle positions for graphical rendering
    • appendNozzle

      private static void appendNozzle(Document document, Element parent, String nozzleId, Set<String> usedIds, Map<String,double[]> nozzlePositions)
      Appends a Nozzle child element to the parent equipment element with optional position.
      Parameters:
      document - the XML document
      parent - the equipment element
      nozzleId - the nozzle ID
      usedIds - set of used IDs
      nozzlePositions - map of nozzle positions (may be null)
    • appendSimulationResults

      private static void appendSimulationResults(Document document, Element genericAttributes, ProcessEquipmentInterface unit)
      Appends simulation result attributes (P, T, flow) from equipment outlet streams.
      Parameters:
      document - the XML document
      genericAttributes - the GenericAttributes element to append to
      unit - the process equipment
    • appendMechanicalDesignAttributes

      private static void appendMechanicalDesignAttributes(Document document, Element parent, ProcessEquipmentInterface unit)
      Appends a GenericAttributes set with mechanical design parameters for the equipment. Only attributes with non-zero/non-default values are exported.
      Parameters:
      document - the XML document
      parent - the equipment element
      unit - the process equipment
    • appendEquipmentBarFromSimulation

      private static void appendEquipmentBarFromSimulation(Document document, Element element, ProcessEquipmentInterface unit, DexpiLayoutEngine.EquipmentPosition position, String labelId, String equipmentId)
      Appends an EquipmentBarLabel using simulation results from the equipment outlet.
      Parameters:
      document - the XML document
      element - the equipment element
      unit - the process equipment
      position - the equipment position
      labelId - the unique label ID
      equipmentId - the equipment element ID
    • collectMechanicalDesignRows

      private static List<String[]> collectMechanicalDesignRows(ProcessEquipmentInterface unit)
      Collects mechanical design parameters from equipment for display in the bar label. Returns rows only for parameters that have been set (non-zero, non-default).
      Parameters:
      unit - the process equipment
      Returns:
      list of label-value pairs (may be empty)
    • formatMechValue

      private static String formatMechValue(double value)
      Formats a mechanical design value for display.
      Parameters:
      value - the value to format
      Returns:
      formatted string
    • getEquipmentOutlet

      private static StreamInterface getEquipmentOutlet(ProcessEquipmentInterface unit)
      Gets the outlet stream of a process equipment for simulation result extraction.
      Parameters:
      unit - the process equipment
      Returns:
      the outlet stream, or null if not available
    • reverseMapComponentClass

      private static String reverseMapComponentClass(ProcessEquipmentInterface unit)
      Returns the DEXPI ComponentClass string for a native NeqSim equipment type.
      Parameters:
      unit - the process equipment
      Returns:
      the DEXPI ComponentClass name
    • isValveType

      private static boolean isValveType(ProcessEquipmentInterface unit)
      Returns true if the unit represents a DEXPI piping component (valve) rather than an Equipment element. In the DEXPI schema, valves are PipingComponent elements and should be embedded inside PipingNetworkSegment elements rather than exported as top-level Equipment.
      Parameters:
      unit - the process equipment to check
      Returns:
      true if the unit should be rendered as a PipingComponent
    • buildValvePipingComponent

      private static Element buildValvePipingComponent(Document document, ProcessEquipmentInterface unit, Set<String> usedIds, String inletNozzleId, List<String> outletNozzleIds, DexpiLayoutEngine.EquipmentPosition position, int labelIndex, Map<String,double[]> nozzlePositions)
      Builds a PipingComponent XML element for a valve unit.
      Parameters:
      document - the XML document
      unit - the valve unit
      usedIds - set of used IDs
      inletNozzleId - the inlet nozzle ID
      outletNozzleIds - the outlet nozzle IDs
      position - the computed layout position (may be null)
      labelIndex - label counter for unique IDs
      nozzlePositions - map of nozzle positions for graphical rendering
      Returns:
      the PipingComponent element
    • registerOutletNozzles

      private static void registerOutletNozzles(ProcessEquipmentInterface unit, List<String> outNozzles, Map<Integer,String> outletStreamToNozzle)
      Registers outlet stream identity hashes to their nozzle IDs.

      For single-outlet equipment, the first (and only) nozzle maps to the gas/primary outlet. For separators, the first nozzle maps to the gas outlet, the second to the liquid outlet, and for three-phase separators, the third maps to the water outlet.

      Parameters:
      unit - the process equipment
      outNozzles - the list of outlet nozzle IDs
      outletStreamToNozzle - map to populate with identity hash to nozzle ID
    • registerNozzlePositions

      private static void registerNozzlePositions(DexpiLayoutEngine.EquipmentPosition position, String inNozzle, List<String> outNozzles, Map<String,double[]> nozzlePositions)
      Registers nozzle positions for connection line geometry.

      Inlet nozzles are placed at the left edge of the equipment shape (x - 10), and outlet nozzles at the right edge (x + 10). Multiple outlets are vertically offset to match the layout.

      Parameters:
      position - the equipment position (may be null)
      inNozzle - the inlet nozzle ID
      outNozzles - the outlet nozzle IDs
      nozzlePositions - map to populate with nozzle ID to {x, y} coordinates
    • registerPassThroughStreams

      private static void registerPassThroughStreams(ProcessSystem processSystem, Map<Integer,String> outletStreamToNozzle)
      Registers pass-through Streams in the outlet-stream-to-nozzle map.

      When a user creates new Stream("gas-out", separator.getGasOutStream()), the wrapping Stream delegates getFluid() to the source. This method detects such wrappers by matching fluid identity and registers the wrapper itself so downstream equipment that took the wrapper as its inlet can be connected.

      Parameters:
      processSystem - the process system
      outletStreamToNozzle - map of outlet stream identity hash to nozzle ID
    • buildConnections

      private static void buildConnections(ProcessSystem processSystem, Map<Integer,String> outletStreamToNozzle, Map<String,String> inletNozzles, List<DexpiXmlWriter.NozzleConnection> connections)
      Builds connections between equipment by matching inlet stream identity to outlet stream nozzles.

      For each equipment that extends TwoPortEquipment, the inlet stream is looked up in the outlet-stream-to-nozzle map to find the upstream nozzle. This correctly resolves branching (e.g. separator gas and liquid outlets going to different downstream equipment).

      Parameters:
      processSystem - the process system
      outletStreamToNozzle - map of outlet stream identity hash to nozzle ID
      inletNozzles - map of equipment name to inlet nozzle ID
      connections - list to populate with connections
    • appendConnectionSystem

      private static void appendConnectionSystem(Document document, Element parent, List<DexpiXmlWriter.NozzleConnection> connections, Set<String> usedIds, Map<String,Element> valvePipingComponents, Map<String,double[]> nozzlePositions)
      Appends a PipingNetworkSystem containing Connection elements for equipment wiring.
      Parameters:
      document - the XML document
      parent - the root element
      connections - the list of connections
      usedIds - set of used IDs
      valvePipingComponents - pre-built PipingComponent elements for valves, keyed by inlet nozzle ID
      nozzlePositions - map of nozzle ID to {x, y} coordinates for line geometry
    • appendPipingNetworkSystem

      private static void appendPipingNetworkSystem(Document document, Element parent, String key, List<DexpiStream> streams, Set<String> usedIds)
    • appendPipingNetworkSegment

      private static void appendPipingNetworkSegment(Document document, Element parent, DexpiStream stream, Set<String> usedIds)
    • appendGenericAttribute

      private static void appendGenericAttribute(Document document, Element parent, String name, String value)
    • appendGenericAttribute

      private static void appendGenericAttribute(Document document, Element parent, String name, String value, String unit)
    • appendNumericAttribute

      private static void appendNumericAttribute(Document document, Element parent, String name, double value, String unit)
    • appendInstruments

      private static void appendInstruments(Document document, Element parent, Map<String, MeasurementDeviceInterface> transmitters, Map<String, ControllerDeviceInterface> controllers, Set<String> usedIds, Map<String, DexpiLayoutEngine.EquipmentPosition> layoutPositions, Map<String,double[]> nozzlePositions, ProcessSystem processSystem)
      Appends DEXPI instrumentation elements for transmitters and controllers.

      Each transmitter becomes a ProcessInstrumentationFunction with a ProcessSignalGeneratingFunction child. Controllers that share a loop tag with a transmitter are linked via SignalConveyingFunction and ActuatingFunction. Finally, an InstrumentationLoopFunction groups each loop's elements.

      Parameters:
      document - the XML document
      parent - the root element to append to
      transmitters - map of tag to transmitter
      controllers - map of tag to controller (may be null)
      usedIds - set of already used XML IDs
      layoutPositions - equipment layout positions keyed by equipment name
      nozzlePositions - nozzle positions keyed by nozzle ID
      processSystem - the process system for stream-to-equipment matching
    • findParentEquipment

      private static String findParentEquipment(MeasurementDeviceInterface device, ProcessSystem processSystem)
      Finds the name of the equipment whose inlet or outlet stream matches the transmitter's stream.
      Parameters:
      device - the measurement device
      processSystem - the process system
      Returns:
      the equipment name, or null if not found
    • appendInstrumentPosition

      private static void appendInstrumentPosition(Document document, Element parent, double x, double y)
      Appends a Position element with Location, Axis, and Reference for an instrument bubble.
      Parameters:
      document - the XML document
      parent - the element to append to
      x - the X coordinate
      y - the Y coordinate
    • appendInstrumentLabelText

      private static void appendInstrumentLabelText(Document document, Element label, String text, double x, double y, String pifId, String[] dependantAttributes)
      Appends a Text element inside an instrument label.
      Parameters:
      document - the XML document
      label - the Label element
      text - the display text
      x - X position of the text
      y - Y position of the text
      pifId - the parent ProcessInstrumentationFunction ID
      dependantAttributes - the DependantAttribute names for TextStringFormatSpecification
    • appendSignalNode

      private static void appendSignalNode(Document document, Element parent, String nodeId, double x, double y)
      Appends a signal Node with position inside a ConnectionPoints element.
      Parameters:
      document - the XML document
      parent - the ConnectionPoints element
      nodeId - the unique node ID
      x - the X coordinate
      y - the Y coordinate
    • parseIsaTag

      private static String[] parseIsaTag(String tag)
      Parses an ISA-style tag (e.g. "PT-HP sep") into category, function letters, and loop number.
      Parameters:
      tag - the ISA tag string
      Returns:
      array of [category, functions, loopNumber]
    • deriveControllerTag

      private static String deriveControllerTag(String transmitterTag)
      Derives the controller tag from a transmitter tag. For example, "PT-HP sep" becomes "PC-HP sep", "LT-HP sep" becomes "LC-HP sep".
      Parameters:
      transmitterTag - the transmitter tag
      Returns:
      the expected controller tag, or null if not derivable
    • collectStreamTableData

      private static List<DexpiLayoutEngine.StreamTableEntry> collectStreamTableData(ProcessSystem processSystem)
      Collects stream data for the stream table from process system equipment.

      Iterates through all equipment in the process system, extracting temperature, pressure, flow rate, and phase information from each outlet stream.

      Parameters:
      processSystem - the process system to extract stream data from
      Returns:
      list of stream table entries for rendering
    • buildStreamEntry

      private static DexpiLayoutEngine.StreamTableEntry buildStreamEntry(DecimalFormat df, String streamLabel, StreamInterface stream)
      Builds a single stream table entry from a stream's simulation results.
      Parameters:
      df - the decimal format for numeric values
      streamLabel - the stream label/number
      stream - the stream to extract data from
      Returns:
      the stream table entry, or null if data is unavailable
    • defaultComponentClass

      private static String defaultComponentClass(EquipmentEnum mapped, String elementName)
    • uniqueIdentifier

      private static String uniqueIdentifier(String prefix, String name, Set<String> usedIds)
    • sanitizeIdentifier

      private static String sanitizeIdentifier(String name)
    • appendIEC81346Attributes

      private static void appendIEC81346Attributes(Document document, Element genericAttributes, ProcessEquipmentInterface unit)
      Appends IEC 81346 reference designation attributes to the generic attributes element.

      If the equipment has an IEC 81346 reference designation set (via ReferenceDesignationGenerator), the following attributes are added:

      • IEC81346ReferenceDesignation: The full reference designation string
      • IEC81346FunctionDesignation: The function aspect
      • IEC81346ProductDesignation: The product aspect
      • IEC81346LocationDesignation: The location aspect
      • IEC81346LetterCode: The equipment letter code (e.g. "B", "K", "Q")
      Parameters:
      document - the XML document
      genericAttributes - the parent element for generic attributes
      unit - the process equipment
    • stripHyphens

      private static String stripHyphens(String value)
    • firstNonBlank

      private static String firstNonBlank(String... values)
    • isBlank

      private static boolean isBlank(String value)
    • detectOrientation

      private static String detectOrientation(ProcessEquipmentInterface unit)
      Detects equipment orientation from the type. Per ISO 10628, separators are typically marked vertical (V) while rotating and heat-transfer equipment are horizontal (H).
      Parameters:
      unit - the process equipment
      Returns:
      "V" for vertical, "H" for horizontal, or null if not applicable
    • detectFailPosition

      private static String detectFailPosition(ProcessEquipmentInterface unit)
      Detects valve fail position from the tag name convention per NORSOK Z-003.

      Tags starting with "XV", "ESD", or "HIPPS" are assumed fail-closed (FC). Tags starting with "HV" are assumed fail-open (FO). Other valves return null (no automatic fail position).

      Parameters:
      unit - the valve equipment
      Returns:
      fail position code (FC, FO), or null
    • reverseMapValveClass

      private static String reverseMapValveClass(ProcessEquipmentInterface unit)
      Determines the DEXPI valve ComponentClass from the tag name. Different valve prefixes indicate different valve types per ISA/NORSOK conventions.
      Parameters:
      unit - the valve equipment
      Returns:
      the DEXPI ComponentClass (GlobeValve, GateValve, BallValve, CheckValve, ButterflyValve)
    • detectSafetySystem

      private static boolean detectSafetySystem(String tag)
      Detects whether an instrument tag indicates a Safety Instrumented System (SIS) device rather than a DCS device. Safety tags typically have key letters like XV (shutdown), SD (shutdown), ZS (limit switch on safety valve), or SV (safety valve).
      Parameters:
      tag - the ISA instrument tag
      Returns:
      true if the tag indicates a safety-instrumented function
    • mapComponentClassUri

      private static String mapComponentClassUri(String componentClass)
      Maps a DEXPI ComponentClass name to its RDL URI.
      Parameters:
      componentClass - the DEXPI ComponentClass
      Returns:
      the RDL URI, or null if no mapping exists
    • writeDocument

      private static void writeDocument(Document document, OutputStream outputStream) throws IOException
      Throws:
      IOException