Skip to content

Commit

Permalink
Minor syntax differences and Large amount of work on CSVWriter and as…
Browse files Browse the repository at this point in the history
…sociated ArrayMatrix class
  • Loading branch information
CodeByDrescher committed Nov 30, 2023
1 parent 74a9154 commit 5d6d41e
Show file tree
Hide file tree
Showing 4 changed files with 323 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,27 +133,26 @@ private List<ExportOutput> exportParticleData(OutputContext outputContext, long
double[] allTimes = timeSpecs.getAllTimes();
int beginIndex = timeSpecs.getBeginTimeIndex();
int endIndex = timeSpecs.getEndTimeIndex();
ParticleDataBlock particleDataBlk = dataServerImpl.getParticleDataBlock(user, vcdID,allTimes[beginIndex]);
ParticleDataBlock particleDataBlock = dataServerImpl.getParticleDataBlock(user, vcdID, allTimes[beginIndex]);
VariableSpecs vs = exportSpecs.getVariableSpecs();
VCAssert.assertValid(vs);
if (vs == null) throw new NullPointerException("VariableSpecs object is unexpectedly null!");
String[] variableNames = vs.getVariableNames();
if (variableNames.length == 0) {
throw new IllegalArgumentException("No variables selected");
}
//need array for SimulationDescription, later
final String[] currentVariableName = new String[1];

List<ExportOutput> rval = new ArrayList<>(variableNames.length);
Set<String> species = particleDataBlk.getSpecies();
List<ExportOutput> realValue = new ArrayList<>(variableNames.length);
Set<String> species = particleDataBlock.getSpecies();
ParticleProgress particleProgress = null;

for (String vcellVariableName : variableNames) {

// Get smoldynSpecies
String smoldynSpecies = this.getSmoldynSpecies(vcellVariableName, species);

// Get particle progress
List<Coordinate> particles = particleDataBlk.getCoordinates(smoldynSpecies);
List<Coordinate> particles = particleDataBlock.getCoordinates(smoldynSpecies);
int numberOfParticles = particles.size();
int numberOfTimes = endIndex - beginIndex + 1;
if (particleProgress != null) {
Expand Down Expand Up @@ -197,8 +196,8 @@ private List<ExportOutput> exportParticleData(OutputContext outputContext, long
final char COMMA = ',';
int nextTimeIndex = particleProgress.nextTimeIndex(0, false);
for (int i = beginIndex; i <= endIndex; i++) {
particleDataBlk = dataServerImpl.getParticleDataBlock(user, vcdID,allTimes[i]);
particles = particleDataBlk.getCoordinates(smoldynSpecies);
particleDataBlock = dataServerImpl.getParticleDataBlock(user, vcdID,allTimes[i]);
particles = particleDataBlock.getCoordinates(smoldynSpecies);

if (i >= nextTimeIndex) {
nextTimeIndex = particleProgress.nextTimeIndex(i, true);
Expand Down Expand Up @@ -242,7 +241,7 @@ private List<ExportOutput> exportParticleData(OutputContext outputContext, long

int nextDataIndex = particleProgress.nextDataIndex(0, false);

StringBuilder all = new StringBuilder( );
StringBuilder all = new StringBuilder();
for (int i = 0; i < dataLines.length; i++) {
final char NEWLINE = '\n';
all.append(dataLines[i]);
Expand All @@ -254,9 +253,9 @@ private List<ExportOutput> exportParticleData(OutputContext outputContext, long
}
}
fileDataContainerManager.append(exportOutputCSV.getFileDataContainerID(), all.toString());
rval.add(exportOutputCSV);
realValue.add(exportOutputCSV);
}
return rval;
return realValue;
}

private String getSmoldynSpecies(String vcellName, Set<String> species) throws DataAccessException {
Expand Down
258 changes: 258 additions & 0 deletions vcell-util/src/main/java/org/vcell/util/ArrayMatrix.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
package org.vcell.util;

public class ArrayMatrix<T> {
private static final int DEFAULT_DIMENSION_SIZE = 10;

private final T padValue; // Value to pad the matrix with when needed.
private int length; // The size of the rows
private int width; // The size of the columns
private T[][] data; // in java, this is traditionally row by column

/**
* Creates a matrix using arrays of a default initial size. When new data is added, `null`
* will be used to pad any gaps in the data
*/
public ArrayMatrix(){
this(null);
}

/**
* Creates a matrix using arrays of a default initial size. When new data is added, the provided object
* will be used to pad any gaps in the data
* @param defaultPad the value to pad gaps in the matrix
*/
public ArrayMatrix(T defaultPad){
this(defaultPad, ArrayMatrix.DEFAULT_DIMENSION_SIZE, ArrayMatrix.DEFAULT_DIMENSION_SIZE);
}

/**
* Creates a matrix using arrays of a defined sizes
* @param initialLength the initial number of columns to prepare
* @param initialWidth the initial number of rows to prepare
*/
@SuppressWarnings("unchecked")
public ArrayMatrix(T defaultPad, int initialLength, int initialWidth){
if (initialLength < 0) throw new IllegalArgumentException("InitialLength can not be negative");
if (initialWidth < 0) throw new IllegalArgumentException("InitialWidth can not be negative");
this.padValue = defaultPad;
this.data = (T[][]) new Object[initialWidth][initialLength];
}

/**
* Trims the capacity of this List to be equal to its size; this saves memory
*/
@SuppressWarnings("unchecked")
public void trimToSize(){
int actualWidth = this.data.length;
int actualLength = (actualWidth == 0 || this.data[0] == null) ? 0 : this.data[0].length;
if (this.width == actualWidth && this.length == actualLength) return;
if (this.data.length == 0) return;

T[][] newData = (T[][]) new Object[actualWidth][actualLength];
for (int i = 0; i < actualWidth; i++){
if (this.data[i] == null) continue;
System.arraycopy(this.data[i], 0, newData[i], 0, actualWidth);
}
this.data = newData;
}

/**
* Ensures that this matrix will be resized such that at least (minWidth * minLength) elements can fit inside.
* The resize for the target dimension (if insufficient) will be at least double the current size
* @param minLength the minimum number of columns to prepare
* @param minWidth the minimum number of rows to prepare
*/
@SuppressWarnings("unchecked")
public void ensureCapacity(int minLength, int minWidth){
int actualWidth = this.data.length;
int actualLength = (actualWidth == 0 || this.data[0] == null) ? 0 : this.data[0].length;

if (minWidth <= actualWidth && minLength <= actualLength) return;
int newWidth = Math.max(2*actualWidth, minWidth);
int newLength = Math.max(2*actualLength, minLength);

T[][] newData = (T[][]) new Object[newWidth][newLength];
for (int i = 0; i < actualWidth; i++){
if (this.data[i] == null) continue;
System.arraycopy(this.data[i], 0, newData[i], 0, actualWidth);
}
this.data = newData;
}

/**
* Get the length of the matrix
* @return the length as an int
*/
public int getLength(){
return this.length;
}

/**
* Get the width of the matrix
* @return the width as an int
*/
public int getWidth(){
return this.width;
}

/**
* Checks if the matrix is empty
*/
public boolean isEmpty(){
return this.length == 0 && this.width == 0;
}

/**
* Determines the coordinates of a given equivalent element, or null if not found
* @param element the element to look for
* @return the coordinates in a vcell Pair object
*/
public Pair<Integer, Integer> coordinatesOf(T element){
/*
for (int i = 0; i < this.width; i++){
for (int j = 0; j < this.length; j++){
if (this.argumentsAreEqual(this.data[i][j], element)) return new Pair<>(i,j);
}
}
return null;
*/
return this.coordinatesOf(element, true, false);
}

/**
* Determines the coordinates of a given equivalent element, or null if not found
* @param element the element to look for
* @param traverseRows whether to go row by row (alternatively, column by column)
* @param reverseSearch whether to start at bottom right of matrix (alternative, top left, the normal way)
* @return the coordinates in a vcell Pair object
*/
public Pair<Integer, Integer> coordinatesOf(T element, boolean traverseRows, boolean reverseSearch){
UpdateFunction updater = reverseSearch ? (i) -> i - 1 : (i) -> i + 1;
int startIndexLength = reverseSearch ? this.length - 1 : 0;
int startIndexWidth = reverseSearch ? this.width - 1 : 0;
int startDim1Index = traverseRows ? startIndexWidth : startIndexLength;
int startDim2Index = traverseRows ? startIndexLength : startIndexWidth;
int dim1size = traverseRows ? this.width : this.length;
int dim2size = traverseRows ? this.length : this.width;
ConditionFunction condition1 = (i) -> reverseSearch ? -1 < i : i < dim1size;
ConditionFunction condition2 = (i) -> reverseSearch ? -1 < i : i < dim2size;

for (int i = startDim1Index; condition1.check(i); i = updater.update(i)){
for (int j = startDim2Index; condition2.check(j); j = updater.update(j)){
if (this.argumentsAreEqual((reverseSearch ? this.data[j][i] : this.data[i][j]), element))
return new Pair<>(i,j);
}
}
return null;
}

/**
* Retrieves the value at the given coordinate pair
* @param coordinate the pair (in (row, column) order to use to look up the value
* @throws IndexOutOfBoundsException if the row / column index is invalid
* @return the value at the provided coordinate
*/
public T valueAt(Pair<Integer, Integer> coordinate){
return this.valueAt(coordinate, true);
}

/**
* Retrieves the value at the given coordinate pair
* @param coordinate the pair to use to look up the value
* @param row_mise if the pair is in (row,column) order; else, (column,row) order
* @throws IndexOutOfBoundsException if the row / column index is invalid
* @return the value at the provided coordinate
*/
public T valueAt(Pair<Integer, Integer> coordinate, boolean row_mise){
if (row_mise) return this.valueAt(coordinate.one, coordinate.two);
return this.valueAt(coordinate.two, coordinate.one);
}

/**
* Retrieves the value at the given coordinate pair
* @param row the row index to look up
* @param column the column index to look up
* @throws IndexOutOfBoundsException if the row / column index is invalid
* @return the value at the provided row and column indices.
*/
public T valueAt(int row, int column){
if (row < 0 || row >= this.width) throw new IndexOutOfBoundsException("Invalid row index");
if (column < 0 || column >= this.length) throw new IndexOutOfBoundsException("Invalid column index");
return this.data[row][column];
}

/**
* Determines if a given element equals an entry in the matrix
* @param element the element to look for
* @return whether the element exists in the matrix or not
*/
public boolean contains(T element){
return this.coordinatesOf(element) != null;
}

/**
* Creates a shallow copy of this object
* @return the clone of this ArrayMatrix
*/
@SuppressWarnings("unchecked")
public Object clone(){
ArrayMatrix<T> clone;
try {
clone = (ArrayMatrix<T>) super.clone();
clone.data = this.data.clone();
} catch(CloneNotSupportedException e){
throw new RuntimeException(e);
}
return clone;
}

/**
* Returns an object matrix (2D array) with a copy of the contents of this ArrayMatrix
* @return a 2D array representation of this ArrayMatrix
*/
@SuppressWarnings("unchecked")
public Object[][] to2DArray(){
T[][] array = (T[][])new Object[this.width][this.length];
for (int i = 0; i < this.width; i++) System.arraycopy(data[i], 0, array[i], 0, this.length);
return array;
}

/**
*
* @return
*/
public T[][] to2DArray(T[][] array2D){
if ((array2D == null || array2D.length < this.width) ||
(array2D.length > 0 && (array2D[0] == null || array2D[0].length < this.length))){
// Break down into multiple create new instance calls
} else {
// Array copy over
}
return array2D;
}

///////////////////////////////////////
// Utility Methods / Classes //
///////////////////////////////////////

// Used as a null-safe .equals replacement
private boolean argumentsAreEqual(Object subject, Object target){
if (subject == null)
return target == null;
return subject.equals(target);
}

/**
* What should be performed to 'i' at the end of a loop iteration
*/
protected interface UpdateFunction {
Integer update(Integer integer);
}

/**
* Condition for continuing the for-loop
*/
protected interface ConditionFunction {
boolean check(Integer value);
}
}
29 changes: 29 additions & 0 deletions vcell-util/src/main/java/org/vcell/util/csv/CSVWriter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.vcell.util.csv;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class CSVWriter {
private final char DELIMITER;
private final char ROW_SEPARATOR;
private final BufferedWriter writer;
public CSVWriter(File outputCSVFile) throws IOException {
this(outputCSVFile, false);
}

public CSVWriter(File outputCSVFile, boolean append) throws IOException {
this(outputCSVFile, append, ',', '\n');
}

public CSVWriter(File outputCSVFile, boolean append, char delimiter, char rowSeparator) throws IOException {
this.writer = new BufferedWriter(new FileWriter(outputCSVFile, append));
this.DELIMITER = delimiter;
this.ROW_SEPARATOR = rowSeparator;
}

public void appendToLine(int lineNumber, String value){

}
}
26 changes: 26 additions & 0 deletions vcell-util/src/test/java/org/vcell/util/ArrayMatrixTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.vcell.util;

import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.vcell.test.Fast;

import static org.junit.Assert.*;

@Category(Fast.class)
public class ArrayMatrixTest {

@Test
public void checkConstructorsTest(){
ArrayMatrix<String> stringMatrix0 = new ArrayMatrix<>();
ArrayMatrix<String> stringMatrix1 = new ArrayMatrix<>("m1");
ArrayMatrix<String> stringMatrix2 = new ArrayMatrix<>("m2", 3, 3);
}

@Test
public void checkDimensionsTest(){
ArrayMatrix<String> stringMatrix = new ArrayMatrix<>("", 3, 3);
assertSame(stringMatrix.getWidth(), 0);
assertSame(stringMatrix.getLength(), 0);
}

}

0 comments on commit 5d6d41e

Please sign in to comment.