/*
* 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.datastructures.neuron;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;
import org.apache.log4j.Logger;
import org.neugen.utils.Vrand;
import org.neugen.datastructures.Axon;
import org.neugen.datastructures.CellBase;
import org.neugen.datastructures.Dendrite;
import org.neugen.datastructures.DendriteSection;
import org.neugen.datastructures.Pair;
import org.neugen.datastructures.Region;
import org.neugen.datastructures.Section;
import org.neugen.datastructures.parameter.NeuronParam;
import org.neugen.gui.Trigger;
/**
* Contains the base class for the construction of a neuron. It also contains
* the lower left corner and upper right corner of the cortical column which
* are static class elements.
* The soma of the neuron is constructed by a d-dimensional sphere.
* The axon is given by the class Axon, and the dendrites are given by a list of
* dendrites of the class Dendrite.
*
* @author Jens Eberhard
* @author Alexander Wanner
* @author Sergei Wolf
*/
public class NeuronBase extends CellBase implements Serializable, Neuron {
private static final long serialVersionUID = -4623546473283033478L;
/** Use to log messages. */
protected static Logger logger = Logger.getLogger(NeuronBase.class.getName());
//public final static int d = DataConstants.NEUGEN_DIM;
/** The random number generator. */
protected static transient Vrand drawNumber;
protected static transient Vrand basalRandomNumber;
/** The axon of neuron. */
protected final Axon axon;
/** The list of dendrites of neuron. */
protected final List<Dendrite> dendrites;
/** The list of undefined section of neuron. */
protected final List<Section> undefinedSections;
/** The index of neuron. */
protected int index;
/** The size of neuron. */
protected Point3f neuronSize;
protected boolean collide;
/**
* Constructor.
* It initializes the list of dendrites.
*/
public NeuronBase() {
axon = new Axon();
dendrites = new ArrayList<Dendrite>();
undefinedSections = new ArrayList<Section>();
}
/**
* Function to get the distance distribution of furkations (branchpoints)
* for neuron. The distance is related to the soma of the neuron. It returns an
* array with num_interval + 1 components where the zeroth component is the total
* number of forks of the neuron.
* @param max_dist_from_soma the maximal distance from the soma which is scanned.
* @param num_interval the number of interval between the distance 0 and max_dist_from_soma.
* @param den_or_axon for den_or_axon = 0 scan the dendritic tree, for den_or_axon = 1 scan the axonal
* tree, and for den_or_axon = 2 scan both trees of neuron.
*/
public List<Integer> getForkDistribution(float max_dist_from_soma, int num_interval, int den_or_axon) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Function to get the neuronal distance distribution of furkations (branchpoints)
* for neuron. The distance is measured along the dendrites or axon in three dimensions. It returns an
* array with num_interval + 1 components where the zeroth component is the total
* number of forks of the neuron.
* @param max_dist the maximal distance along the dendrite or axon which is scanned.
* @param num_interval the number of interval between the distance 0 and max_dist_from_soma.
* @param den_or_axon for den_or_axon = 0 scan the dendritic tree, for den_or_axon = 1 scan the axonal
* tree, and for den_or_axon = 2 scan both trees of neuron.
*/
public List<Integer> getForkDistribution2(float max_dist, int num_interval, int den_or_axon) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Function to get the width of the neural tree as a distribution of the distance
* of the compartments for neuron. The distance is related to the soma of the neuron. It returns an
* array with num_interval + 1 components where the zeroth component is the total
* number of segments of the neuron.
* @param max_dist_from_soma the maximal distance from the soma which is scanned.
* @param num_interval the number of interval between the distance 0 and max_dist_from_soma.
* @param den_or_axon for den_or_axon = 0 scan the dendritic tree, for den_or_axon = 1 scan the axonal
* tree, and for den_or_axon = 2 scan both trees of neuron.
* The function counts the number of all compartments intersecting with a given distance from the soma.
*/
public List<Integer> getTotalwidthDistribution(float max_dist_from_soma, int num_interval, int den_or_axon) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Function to get the width of the neural tree as a distribution of the distance
* of the intersecting compartments only. The distance is related to the soma of the neuron. It returns an
* array with num_interval + 1 components where the zeroth component is the
* number of counted segments of the neuron.
* @param max_dist_from_soma the maximal distance from the soma which is scanned.
* @param num_interval the number of interval between the distance 0 and max_dist_from_soma.
* @param den_or_axon for den_or_axon = 0 scan the dendritic tree, for den_or_axon = 1 scan the axonal
* tree, and for den_or_axon = 2 scan both trees of neuron.
* The function counts the number of compartments intersecting with a given distance from the soma. It counts only
* one segment per interval.
*/
public List<Integer> getWidthSistribution(float max_dist_from_soma, int num_interval, int den_or_axon) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public List<Section> getUndefinedSections() {
return undefinedSections;
}
public void getSize() {
// x coord, min z and max z coord (width)
Map<Integer, Pair<Float, Float>> xData = new HashMap<Integer, Pair<Float, Float>>();
// y coord, min x and max x coord (length)
Map<Integer, Pair<Float, Float>> yData = new HashMap<Integer, Pair<Float, Float>>();
// key: z coord, value: min and max y coord (height)
Map<Integer, Pair<Float, Float>> zData = new HashMap<Integer, Pair<Float, Float>>();
for (Dendrite den : dendrites) {
den.getNTSSize(xData, yData, zData);
}
axon.getNTSSize(xData, yData, zData);
/*
int minX = 0;
int maxX = 0;
for(int x : xData.keySet()) {
if(x > maxX) {
maxX = x;
} else if(x < minX) {
minX = x;
}
}
int minY = 0;
int maxY = 0;
for(int y : yData.keySet()) {
if(y > maxY) {
maxY = y;
} else if(y < minY) {
minY = y;
}
}
int minZ = 0;
int maxZ = 0;
for(int z : zData.keySet()) {
if(z > maxZ) {
maxZ = z;
} else if(z < minZ) {
minZ = z;
}
}
Point3f lowLeftCorner = new Point3f(minX, minY, minZ);
Point3f upRightCorner = new Point3f(maxX, maxY, maxZ);
Pair<Point3f, Point3f> cornerValues = new Pair<Point3f, Point3f>(lowLeftCorner, upRightCorner);
*
*/
float length = 0.0f;
for (Pair<Float, Float> minMaxXCoord : yData.values()) {
float localWidth = Math.abs(minMaxXCoord.second - minMaxXCoord.first);
if (length < localWidth) {
length = localWidth;
}
}
float width = 0.0f;
for (Pair<Float, Float> minMaxXCoord : xData.values()) {
float localWidth = Math.abs(minMaxXCoord.second - minMaxXCoord.first);
if (width < localWidth) {
width = localWidth;
}
}
float height = 0.0f;
for (Pair<Float, Float> minMaxXCoord : zData.values()) {
float localWidth = Math.abs(minMaxXCoord.second - minMaxXCoord.first);
if (height < localWidth) {
height = localWidth;
}
}
neuronSize = new Point3f(length, width, height);
//return cornerValues;
}
public float getVolume() {
float volume = 0.0f;
for (Dendrite curDen : dendrites) {
volume += curDen.getNTSVolume();
}
//volume += axon.getNTSVolume();
return volume;
}
/**
* Get the value of index
*
* @return the value of index
*/
@Override
public int getIndex() {
return index;
}
/**
* Set the value of index
*
* @param index new value of index
*/
@Override
public void setIndex(int index) {
this.index = index;
}
/**
* Get the value of drawNumber
*
* @return the value of drawNumber
*/
public Vrand getDrawNumber() {
return drawNumber;
}
public static void setDrawNumber(Vrand drawNumber) {
NeuronBase.drawNumber = drawNumber;
}
public static void deleteData() {
//drawNumber = null;
basalRandomNumber = null;
Axon.setDrawNumber(null);
}
/**
* Get the value of axon
*
* @return the value of axon
*/
@Override
public Axon getAxon() {
return axon;
}
/**
* Get the value of denList
*
* @return the value of denList
*/
@Override
public List<Dendrite> getDendrites() {
return dendrites;
}
@Override
public int getNumberOfAllDenSegments() {
int numberOfAllDenSegments = 0;
int numDendrites = dendrites.size();
for (int j = 0; j < numDendrites; j++) {
Dendrite dendrite = dendrites.get(j);
numberOfAllDenSegments += dendrite.getNumOfSegments();
}
return numberOfAllDenSegments;
}
public int getNumberOfAllDenSections() {
int numberOfAllDenSections = 0;
int numDendrites = dendrites.size();
for (int j = 0; j < numDendrites; j++) {
Dendrite dendrite = dendrites.get(j);
numberOfAllDenSections += dendrite.getNumOfSections();
}
return numberOfAllDenSections;
}
/**
* Function for setting a neuron. It sets the axon and creates the dendrites.
* For the subclasses of Neuron this function must be over-written.
*/
@Override
public void setNeuron() {
logger.info("set for neuron");
Point3f somaMid = new Point3f(soma.getMid());
Point3f axonEnd = new Point3f(somaMid);
Point3f axonStart = new Point3f(somaMid);
float somaRadius = soma.getMeanRadius();
Vector3f deviation = new Vector3f(getParam().getDeviation().getX(), getParam().getDeviation().getY(), getParam().getDeviation().getZ());
deviation.scale(somaRadius);
if (drawNumber == null) {
logger.info("random number is null!");
drawNumber = new Vrand(getParam().getSeedValue());
}
int up_down = drawNumber.pm_onedraw();
axonEnd.x += getParam().getAxonParam().getFirstGen().getLenParam().getX() * drawNumber.fpm_onedraw();
axonEnd.y += getParam().getAxonParam().getFirstGen().getLenParam().getY() * drawNumber.fpm_onedraw();
axonEnd.z = somaMid.z + up_down * getParam().getAxonParam().getFirstGen().getLenParam().getZ() * (drawNumber.fdraw() + 0.5f);
axonStart.z += up_down * somaRadius;
//logger.info("set axon");
axon.set(axonStart, axonEnd, getParam().getAxonParam());
//logger.info("set dendirte");
for (int i = 0; i < getParam().getNumberOfDendrites(); ++i) {
Dendrite curDen = new Dendrite();
curDen.setDendrite(getParam().getDendriteParam(), soma, deviation, false);
dendrites.add(curDen);
}
}
@Override
public NeuronParam getParam() {
return NeuronParam.getInstance();
}
/**
* Function for information of neuron. It gives the total length of dendrites and
* the length of the axon, and further informations.
*/
@Override
public void infoNeuron() {
// axon measurements
Point3f axonRadius = axon.getRadius();
//logger.info("axon avg rad: " + axonRadius.toString());
float axonSurfaceArea = axon.getSurfaceArea();
float totalAxonLength = axon.getTotalLength();
int totalAxonSec = axon.getNumOfSections();
int totalAxonBranch = axon.getNBranch();
// dendrite measurements
// The total length of all dendrites including their branches.
Point3f basalDenRadius = new Point3f();
Point3f apicalRadius = new Point3f();
float totalDenLength = 0.0f;
float denSurfaceArea = 0.0f;
int denNParts = 0;
int denNBranch = 0;
int denNSec = 0;
int denNSeg = 0;
int numApical = 0;
int numBasal = 0;
for (int i = 0; i < dendrites.size(); ++i) {
Dendrite curDen = dendrites.get(i);
//logger.info("den radius: " + curDen.getRadius().toString());
if (curDen.getFirstSection() != null) {
if (curDen.getFirstSection().getSectionType() != null) {
if (curDen.getFirstSection().getSectionType().equals(Section.SectionType.APICAL)) {
numApical++;
apicalRadius.add(curDen.getRadius());
} else if (curDen.getFirstSection().getSectionType().equals(Section.SectionType.BASAL)) {
numBasal++;
basalDenRadius.add(curDen.getRadius());
//logger.info("basal dendrite!");
}
}
totalDenLength += curDen.getTotalLength();
denSurfaceArea += curDen.getSurfaceArea();
denNParts += curDen.getNParts();
denNBranch += curDen.getNBranch();
denNSec += curDen.getNumOfSections();
denNSeg += curDen.getNumOfSegments();
}
}
if (numApical != 0) {
apicalRadius.scale(1.0f / (float) numApical);
}
if (numBasal != 0) {
basalDenRadius.scale(1.0f / (float) numBasal);
}
/*
float averageRadius = 0.0f;
averageDenRadius /= dendrites.size();
if(Float.isNaN(averageAxonRadius) || Float.isInfinite(averageAxonRadius) || averageAxonRadius == 0.0f) {
averageAxonRadius = 0.0f;
averageRadius = averageDenRadius;
} else {
averageRadius = (averageAxonRadius + averageDenRadius) / 2.0f;
}
*/
// soma measurements
float somaSurfaceArea = soma.getSurfaceArea();
String somaMid = soma.getMid().toString();
float totalSomaLength = 0.0f;
if (soma.getCylindricRepresentant() == null) {
totalSomaLength = soma.cylindricRepresentant().getLength();
} else {
totalSomaLength = soma.getCylindricRepresentant().getLength();
}
int somaNSeg = 0;
if (soma.getCylindricRepresentant() != null) {
somaNSeg = soma.getCylindricRepresentant().getSegments().size();
}
// neuron measurements
float neuronLength = totalAxonLength + totalDenLength + totalSomaLength;
float neuronSurfaceArea = axonSurfaceArea + denSurfaceArea + somaSurfaceArea;
float somaRad = soma.getAvgRadius();
getSize();
StringBuilder ret = new StringBuilder();
ret.append("Info for ").append(index + 1).append(".th neuron:" + "\n"
+ " total length of neuron: ").append(neuronLength).append(" µm\n"
+ " total length of dendrites: ").append(totalDenLength).append(" µm\n"
+ " total length of axon: ").append(totalAxonLength).append(" µm\n"
+ " surface area of neuron: ").append(neuronSurfaceArea).append(" µm^2\n"
+ " surface area of dendrites: ").append(denSurfaceArea).append(" µm^2\n"
+ " surface area of axon: ").append(axonSurfaceArea).append(" µm^2\n"
+ " surface area of soma: ").append(somaSurfaceArea).append(" (µm^2)\n"
+ " soma at: ").append(somaMid).append("\n"
+ " number of dendrites starting from soma: ").append(dendrites.size()).append("\n"
+ " number of sections of all dendrites: ").append(denNSec).append("\n"
+ " number of segments of all dendrites: ").append(denNSeg).append("\n"
+ " number of branches of all dendrites: ").append(denNBranch).append("\n"
+ " number of branches of axon: ").append(totalAxonBranch).append("\n"
+ " number of sections of axon: ").append(totalAxonSec).append("\n"
+ " number of segments of axon: ").append(axon.getNumOfSegments()).append("\n"
+ " number of segments of soma: ").append(somaNSeg).append("\n"
+ " total number of bifurcation: ").append(denNBranch + totalAxonBranch).append("\n"
+ " total number of brunch: ").append(denNSec + totalAxonSec).append("\n"
+ " length (width) of the neuron: ").append(neuronSize.x).append("\n"
+ " width (depth) of the neuron: ").append(neuronSize.y).append("\n"
+ " height of the neuron: ").append(neuronSize.z).append("\n"
+ " (neuroMorpho.org measurements)").append("\n"
+ " soma avg radius: ").append(somaRad).append("\n"
+ " axon radius (max,min,avg): ").append(axonRadius.toString()).append("\n"
+ " apical radius (max,min,avg): ").append(apicalRadius.toString()).append("\n"
+ " basal radius (max,min,avg): ").append(basalDenRadius.toString()).append("\n"
+ " volume of the neuron: ").append(getVolume()).append(" µm^3\n");
Trigger trigger = Trigger.getInstance();
trigger.outPrintln(ret.toString());
}
@Override
public boolean collide() {
return collide;
}
@Override
public void setCollide(boolean c) {
this.collide = c;
}
}