/*
* Copyright (c) 2005–2012 Goethe Center for Scientific Computing - Simulation and Modelling (G-CSC Frankfurt)
* Copyright (c) 2012-2015 Goethe Center for Scientific Computing - Computational Neuroscience (G-CSC Frankfurt)
*
* This file is part of NeuGen.
*
* NeuGen is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* as published by the Free Software Foundation.
*
* see: http://opensource.org/licenses/LGPL-3.0
* file://path/to/NeuGen/LICENSE
*
* NeuGen is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* This version of NeuGen includes copyright notice and attribution requirements.
* According to the LGPL this information must be displayed even if you modify
* the source code of NeuGen. The copyright statement/attribution may not be removed.
*
* Attribution Requirements:
*
* If you create derived work you must do the following regarding copyright
* notice and author attribution.
*
* Add an additional notice, stating that you modified NeuGen. In addition
* you must cite the publications listed below. A suitable notice might read
* "NeuGen source code modified by YourName 2012".
*
* Note, that these requirements are in full accordance with the LGPL v3
* (see 7. Additional Terms, b).
*
* Publications:
*
* S. Wolf, S. Grein, G. Queisser. NeuGen 2.0 -
* Employing NeuGen 2.0 to automatically generate realistic
* morphologies of hippocapal neurons and neural networks in 3D.
* Neuroinformatics, 2013, 11(2), pp. 137-148, doi: 10.1007/s12021-012-9170-1
*
*
* J. P. Eberhard, A. Wanner, G. Wittum. NeuGen -
* A tool for the generation of realistic morphology
* of cortical neurons and neural networks in 3D.
* Neurocomputing, 70(1-3), pp. 327-343, doi: 10.1016/j.neucom.2006.01.028
*
*/
package org.neugen.parsers;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.vecmath.Point3f;
import org.apache.log4j.Logger;
import org.neugen.datastructures.Axon;
import org.neugen.datastructures.Cellipsoid;
import org.neugen.datastructures.Cons;
import org.neugen.datastructures.Dendrite;
import org.neugen.datastructures.Net;
import org.neugen.datastructures.neuron.Neuron;
import org.neugen.datastructures.Pair;
import org.neugen.datastructures.Section;
import org.neugen.datastructures.Segment;
/**
* Class to export data of neuroal net to a simplified hoc format.
*
* @author Sergei Wolf
*/
public final class SimpleHocWriter {
/** Use to log messages. */
private final static Logger logger = Logger.getLogger(SimpleHocWriter.class.getName());
public static final int d = 3;
public static final char AXON_TYPE = 'a';
public static final char SOMA_TYPE = 's';
public static final char DENDRITIC_TYPE = 'd';
public DecimalFormat df;
public int globalID;
public int somaID;
//char parentType;
//int parentID;
///map for the parentIDs
public Map<Section, Pair<Integer, Character>> sectionIds;
/// Function to increment global ID
public int incrementGlobalID() {
return globalID++;
}
public int getGlobalID() {
return globalID;
}
/// Function to save the integer id
public void insertIntoSecID(Section sec, int secID, char type) {
//(*section_ids)[sec] = pair<unsigned int, char>(secID, type);
sectionIds.put(sec, new Pair<Integer, Character>(secID, type));
}
public SimpleHocWriter() {
String pattern = "###.###";
Locale loc = new Locale("en", "US");
NumberFormat nf = NumberFormat.getNumberInstance(loc);
df = (DecimalFormat) nf;
df.applyPattern(pattern);
sectionIds = new HashMap<Section, Pair<Integer, Character>>();
}
/**
* Function to get the parent section id in integer format and the type of the section
*/
private Pair<Integer, Character> getParentSectionID(Section sec) {
if (sec.getParentalLink() != null && sec.getParentalLink().getParental() != null) {
Section parentSec = sec.getParentalLink().getParental();
return sectionIds.get(parentSec);
/*
int parID = parentSec.getId();
Character type;
Section.SectionType parSecType = parentSec.getSectionType();
if (parSecType == Section.SectionType.SOMA) {
type = SOMA_TYPE;
} else if (parSecType == Section.SectionType.MYELINIZED || parSecType == Section.SectionType.NOT_MYELINIZED) {
type = AXON_TYPE;
} else if (parSecType == Section.SectionType.APICAL || parSecType == Section.SectionType.BASAL || parSecType == Section.SectionType.OBLIQUE) {
type = DENDRITIC_TYPE;
} else {
type = null;
}
Pair<Integer, Character> pData = new Pair<Integer, Character>(parID, type);
return pData;
*
*/
} //soma is parent
else {
Pair<Integer, Character> somaData = new Pair<Integer, Character>();
somaData.first = somaID;
somaData.second = SOMA_TYPE;
return somaData;
}
}
/**
* Function to write data of segment into shoc file
*
* @param fw the stream for the shoc file
* @param start_end for 0 write data of start of segment, for 1 write data of end of segment.
* @throws IOException
*/
public final void writetoshocSegment(Writer fw, int start_end, Segment segment) throws IOException {
if (start_end == 0) {
fw.write("\t");
Point3f sstart = segment.getStart();
fw.write(df.format(sstart.x) + " " + df.format(sstart.y) + " " + df.format(sstart.z) + " ");
float rad = segment.getStartRadius() * 2;
testRad(rad);
fw.write(df.format(rad) + "\n");
}
if (start_end == 1) {
fw.write("\t");
Point3f send = segment.getEnd();
fw.write(df.format(send.x) + " " + df.format(send.y) + " " + df.format(send.z) + " ");
float rad = segment.getEndRadius() * 2;
testRad(rad);
fw.write(df.format(rad) + "\n");
}
}
/**
* Function to write the data of dendrite into a shoc file.
* @param fw the stream for the shoc file.
* @param neuron the neuron of neural network
* @throws IOException
*/
public final void writetoshocDendrite(Writer fw, Neuron neuron) throws IOException {
Integer parentID = null;
Character parentType = null;
for (Dendrite dendrite : neuron.getDendrites()) {
Section firstSection = dendrite.getFirstSection();
Section.Iterator secIterator = firstSection.getIterator();
while (secIterator.hasNext()) {
Section section = secIterator.next();
int nsegs = section.getSegments().size();
if (nsegs > 0) {
Pair<Integer, Character> parentData = getParentSectionID(section);
if (parentData == null) {
logger.info("parentData ist null");
//int somaId = neuron.getSoma().getEllipsoid().getId();
int somaId = somaID;
parentData = new Pair<Integer, Character>(somaId, SOMA_TYPE);
}
parentID = parentData.first;
parentType = parentData.second;
if (parentType.equals(SOMA_TYPE)) {
Point3f somaMid = neuron.getSoma().getMid();
logger.info("(dend data)parent is soma, somaMid: " + somaMid);
Point3f segStart = section.getSegments().get(0).getStart();
logger.info("dend seg start: " + segStart.toString());
boolean compareP = somaMid.equals(segStart);
if (compareP) {
logger.info("die punkte sind gleich");
segStart.z = somaMid.z + 5;
} else {
logger.info("die punkte sind verschieden");
segStart.x = somaMid.x;
segStart.y = somaMid.y;
segStart.z = somaMid.z + 5;
//continue;
}
}
//int id = section.getId();
int id = globalID;
fw.write("begin dendrite " + id + "\n");
fw.write("\tparent " + parentType.toString() + " " + parentID.toString() + "\n");
fw.write("\t" + nsegs + "\n");
for (Segment segment : section.getSegments()) {
writetoshocSegment(fw, 0, segment);
}
Segment segment = section.getSegments().get(nsegs - 1);
writetoshocSegment(fw, 1, segment);
fw.write("end\n");
fw.flush();
insertIntoSecID(section, globalID, DENDRITIC_TYPE);
incrementGlobalID();
}
}
}
}
public void testRad(float rad) {
if (rad < 0.1f) {
logger.info("radius ist kleiner als 0.1");
}
}
/**
* Function to write the data of axon into a shoc file.
* @param fw the stream for the shoc file.
* @throws IOException
*/
public final void writetoshocAxon(Writer fw, Neuron neuron) throws IOException {
Axon axon = neuron.getAxon();
if (axon.getFirstSection() == null) {
return;
}
Section firstSection = axon.getFirstSection();
Section.Iterator secIterator = firstSection.getIterator();
// loop over all sections of axon neuron
while (secIterator.hasNext()) {
Section section = secIterator.next();
int nsegs = section.getSegments().size();
if (nsegs > 0) {
Pair<Integer, Character> parentData = this.getParentSectionID(section);
if (parentData == null) {
logger.info("parentData is null-> soma is parent!: " + section.getName());
int somaId = somaID;
/*
if (neuron.getSoma().getCylindricRepresentant() == null) {
somaId = neuron.getSoma().getEllipsoid().getId();
} else {
somaId = neuron.getSoma().getCylindricRepresentant().getId();
}
*
*/
parentData = new Pair<Integer, Character>(somaId, SOMA_TYPE);
}
Integer parentID = parentData.first;
/*
if (parentID == null) {
logger.info("parent id is null");
}
*/
Character parentType = parentData.second;
if (parentType.equals(SOMA_TYPE)) {
Point3f somaMid = neuron.getSoma().getMid();
logger.info("(axon data)parent is soma, somaMid: " + somaMid);
Point3f segStart = section.getSegments().get(0).getStart();
logger.info("axon seg start: " + segStart.toString());
boolean compareP = somaMid.equals(segStart);
if (compareP) {
logger.info("die punkte sind gleich");
segStart.z = somaMid.z + 5;
} else {
logger.info("die punkte sind verschieden");
segStart.x = somaMid.x;
segStart.y = somaMid.y;
segStart.z = somaMid.z + 5;
//continue;
}
}
//original sec id
//int id = section.getId();
int id = globalID;
fw.write("begin axon " + id + "\n");
fw.write("\tparent " + parentType.toString() + " " + parentID.toString() + "\n");
fw.write("\t" + nsegs + "\n");
for (Segment segment : section.getSegments()) {
writetoshocSegment(fw, 0, segment);
}
Segment segment = section.getSegments().get(nsegs - 1);
writetoshocSegment(fw, 1, segment);
insertIntoSecID(section, globalID, AXON_TYPE);
incrementGlobalID();
fw.write("end\n");
fw.flush();
}
}
}
/**
* Function to write the data of cellipsoid into a simplified hoc file.
* @param fw the stream for the hoc file.
* @param neuron the neuron of net
* @throws IOException
*/
public final void writetoshocSoma(Writer fw, Neuron neuron) throws IOException {
Cellipsoid soma = neuron.getSoma();
Section section = soma.getEllipsoid();
/*
Section section = soma.getCylindricRepresentant();
if (section == null) {
section = soma.getEllipsoid();
}
*
*/
int nsegs = section.getSegments().size();
//original id
//int id = section.getId();
//global id
int id = globalID;
fw.write("begin soma " + id + "\n");
fw.write("\t" + (nsegs - 1) + "\n");
for (Segment segment : section.getSegments()) {
writetoshocSegment(fw, 0, segment);
}
/*
Segment segment = section.getSegments().get(nsegs - 1);
float[] send = segment.getEnd();
fw.write("\t");
for (int i = 0; i < d; ++i) {
fw.write(send[i] + " ");
}
fw.write(segment.getEndRadius() * 2 + "\n");
*/
somaID = globalID;
incrementGlobalID();
fw.write("end\n");
fw.flush();
}
public final void writetoshocExp2Synapses(Net net, Writer fw) throws IOException {
int synId = Section.getSecCounter();
List<Cons> synapseList = net.getSynapseList();
for (int j = 0; j < synapseList.size(); j++) {
Cons synapse = synapseList.get(j);
if (synapse.getNeuron1() == null) {
continue;
}
int c_idx = 0;
for (Segment denSeg : synapse.getNeuron2DenSection().getSegments()) {
if (denSeg.getId() == synapse.getNeuron2DenSectionSegment().getId()) {
break;
}
c_idx++;
}
Section denSec = synapse.getNeuron2DenSection();
Segment denSeg = denSec.getSegments().get(c_idx);
Point3f denEnd = denSeg.getEnd();
float denEndRad = denSeg.getEndRadius();
Segment axonSeg = synapse.getNeuron1AxSegment();
Point3f axonEnd = axonSeg.getEnd();
float axonEndRad = axonSeg.getEndRadius();
int nsegs = 1;
fw.append("begin synapse " + synId + "\n"
+ "\tparent a " + synapse.getNeuron1AxSection().getId() + "\n"
+ "\tchild d " + synapse.getNeuron2DenSection().getId() + "\n"
+ "\t" + nsegs + "\n"
+ "\t" + axonEnd.x + " " + axonEnd.y + " " + axonEnd.z + " " + (axonEndRad * 2) + "\n"
+ "\t" + denEnd.x + " " + denEnd.y + " " + denEnd.z + " " + (denEndRad * 2) + "\n"
+ "end\n");
synId++;
}
fw.flush();
}
public final void writetoshocUndefSection(Writer fw, Neuron neuron) throws IOException {
Integer parentID = null;
Character parentType = null;
for (Section section : neuron.getUndefinedSections()) {
int nsegs = section.getSegments().size();
if (nsegs > 0) {
Pair<Integer, Character> parentData = getParentSectionID(section);
if (parentData == null) {
logger.info("parentData ist null");
//int somaId = neuron.getSoma().getEllipsoid().getId();
int somaId = somaID;
parentData = new Pair<Integer, Character>(somaId, SOMA_TYPE);
}
parentID = parentData.first;
parentType = parentData.second;
if (parentType.equals(SOMA_TYPE)) {
Point3f somaMid = neuron.getSoma().getMid();
logger.info("(dend data)parent is soma, somaMid: " + somaMid);
Point3f segStart = section.getSegments().get(0).getStart();
logger.info("dend seg start: " + segStart.toString());
boolean compareP = somaMid.equals(segStart);
if (compareP) {
logger.info("die punkte sind gleich");
segStart.z = somaMid.z + 5;
} else {
logger.info("die punkte sind verschieden");
segStart.x = somaMid.x;
segStart.y = somaMid.y;
segStart.z = somaMid.z + 5;
//continue;
}
}
//int id = section.getId();
int id = globalID;
fw.write("begin dendrite " + id + "\n");
fw.write("\tparent " + parentType.toString() + " " + parentID.toString() + "\n");
fw.write("\t" + nsegs + "\n");
for (Segment segment : section.getSegments()) {
writetoshocSegment(fw, 0, segment);
}
Segment segment = section.getSegments().get(nsegs - 1);
writetoshocSegment(fw, 1, segment);
fw.write("end\n");
fw.flush();
insertIntoSecID(section, globalID, DENDRITIC_TYPE);
incrementGlobalID();
}
}
}
public final void writetoshocNetGeometry(Writer fw, Net net) throws IOException {
for (Neuron neuron : net.getNeuronList()) {
writetoshocSoma(fw, neuron);
writetoshocAxon(fw, neuron);
writetoshocDendrite(fw, neuron);
writetoshocUndefSection(fw, neuron);
fw.flush();
}
writetoshocExp2Synapses(net, fw);
}
public void writeNet(Net net, File file) {
logger.info("Simplifedhoc File: " + file.getAbsolutePath());
Writer fw = null;
try {
fw = new FileWriter(file);
writetoshocNetGeometry(fw, net);
fw.flush();
fw.close();
} catch (Exception e) {
logger.error("Could not create file: " + e, e);
}
}
public static void main(String args[]) {
MorphMLReader netBuilder = new MorphMLReader();
String fname = "bla.xml";
netBuilder.runMorphMLReader(fname);
Net net = netBuilder.getNet();
System.out.println("Size of the neural net: " + net.getNeuronList().size());
File file = new File("CA1Migliore.shoc");
SimpleHocWriter exportSHoc = new SimpleHocWriter();
exportSHoc.writeNet(net, file);
}
}