/*
* 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;
import org.neugen.datastructures.neuron.Neuron;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.vecmath.Point3f;
import org.apache.log4j.Logger;
import org.neugen.utils.Frand;
import org.neugen.datastructures.parameter.NetParam;
/**
* This class contains the construction of a neural net, for
* the plotting routines, and for a neural velocity field.
*
* @author Jens Eberhard
* @author Simone Eberhard
* @author Alexander Wanner
* @author Sergei Wolf
*/
public class NetBase implements Serializable, Net {
private static final long serialVersionUID = -7041930069294524614L;
/** use to log messages */
private final static Logger logger = Logger.getLogger(NetBase.class.getName());
/** random number generator */
protected transient Frand drawNumber;
protected int totalNumberOfDenSegments;
protected int totalNumberOfSomataSegments;
protected int totalNumberOfAxonalSegments;
protected final List<Neuron> neuronList;
protected final List<Cons> synapseList;
protected final List<String> typeCellNames;
protected transient NetParam netParam;
protected Region region;
protected int[] typeCellNumbers;
protected int[] cellOffsets;
protected long[][] synNumbers;
/** number of synapses */
protected int nsynapse;
protected int nnf_synapses;
/** number of neurons */
protected int nneuron;
/**
* Constructor. It initializes the neural net and uses the various subclasses
* of neuron to create a cortical column.
*/
public NetBase() {
Section.resetSecCounter();
Segment.resetSegCounter();
neuronList = new ArrayList<Neuron>();
synapseList = new ArrayList<Cons>();
typeCellNames = new ArrayList<String>();
netParam = NetParam.getInstance();
Region.setInstance(null);
region = new Region();
Region.setInstance(region);
cellOffsets = new int[1];
cellOffsets[0] = 0;
typeCellNames.add("imported cell");
}
@Override
public void destroy() {
drawNumber = null;
netParam = null;
if (neuronList != null) {
for (Neuron neuron : neuronList) {
List<Dendrite> dendriteList = neuron.getDendrites();
for (Dendrite dendrite : dendriteList) {
Section.Iterator secIterator = dendrite.getFirstSection().getIterator();
while (secIterator.hasNext()) {
Section section = secIterator.next();
section.getSegments().clear();
}
dendrite = null;
}
dendriteList.clear();
Axon axon = neuron.getAxon();
if (axon.getFirstSection() != null) {
Section.Iterator secIterator = axon.getFirstSection().getIterator();
while (secIterator.hasNext()) {
Section section = secIterator.next();
section.getSegments().clear();
}
}
axon = null;
neuron = null;
}
neuronList.clear();
}
if (synapseList != null) {
synapseList.clear();
}
if (typeCellNames != null) {
typeCellNames.clear();
}
System.gc();
}
@Override
public List<String> getTypeCellNames() {
return typeCellNames;
}
@Override
public Region getRegion() {
return region;
}
@Override
public int[] getCellOffsets() {
return cellOffsets;
}
@Override
public List<Cons> getSynapseList() {
return synapseList;
}
/**
* Get number of synapses
*
* @return number of synapses
*/
@Override
public long getNumOfSynapses(int presynapticType, int postSynapticType) {
return synNumbers[presynapticType][postSynapticType];
}
public Frand getDrawNumber() {
return drawNumber;
}
public void setDrawNumber(Frand drawNumber) {
this.drawNumber = drawNumber;
}
@Override
public List<Neuron> getNeuronList() {
return neuronList;
}
@Override
public int getNumNeurons() {
return neuronList.size();
}
@Override
public int getTotalNumOfAxonalSegments() {
return totalNumberOfAxonalSegments;
}
@Override
public int getTotalNumOfDenSegments() {
return totalNumberOfDenSegments;
}
@Override
public int getTotalNumOfSomataSegments() {
return totalNumberOfSomataSegments;
}
@Override
public int getTotalNumOfSegments() {
return totalNumberOfAxonalSegments + totalNumberOfDenSegments + totalNumberOfSomataSegments;
}
/**
* Function sets the total number of dendrite, axon
* and soma segments of the neural net
*/
@Override
public void setTotalNumOfSegments() {
totalNumberOfSomataSegments = 0;
totalNumberOfAxonalSegments = 0;
totalNumberOfDenSegments = 0;
for (Neuron neuron : neuronList) {
Axon axon = neuron.getAxon();
Cellipsoid soma = neuron.getSoma();
//totalNumberOfAxonalSegments += axon.getNumberOfAxonalSegments();
totalNumberOfAxonalSegments += axon.getNumOfSegments();
totalNumberOfSomataSegments += soma.getNumberOfSomaSegments();
totalNumberOfDenSegments += neuron.getNumberOfAllDenSegments();
}
}
@Override
public void interconnect() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void generate() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Map<String, Float> computeAPSN() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public int getTypeOfNeuron(int indexOfNeuron) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public WriteToHoc getHocData() {
throw new UnsupportedOperationException("Not supported yet.");
}
public class AxonSegmentData {
public Neuron neuron;
public Section section;
public Segment segment;
public Point3f end;
public AxonSegmentData(Neuron neuron, Section section, Segment segment) {
this.neuron = neuron;
this.section = section;
this.segment = segment;
end = segment.getEnd();
}
public Point3f get3DVec() {
return end;
}
@Override
public String toString() {
String ret;
ret = "neuron_idx = " + neuron.getIndex() + " local_segment=" + segment.getId();
if (section == null) {
ret += "section = null";
} else {
ret += "section = " + section.getId();
}
ret += "end = ";
ret += end.toString();
return ret;
}
public Segment getSegment() {
return segment;
}
}
public void calculateSomaticDistance(Cons synapse) {
//logger.info("neuron1_idx: " + iter.neuron1_idx);
//logger.info("neuron2_idx: " + iter.neuron2_idx);
float ax_soma_dist = 0;
Section axonSec = synapse.getNeuron1AxSection();
if (axonSec.getParentalLink() != null) {
ax_soma_dist = axonSec.getParentalLink().getPolySomaDist();
//logger.info("ax_soma_dist: " + ax_soma_dist);
}
int axSegPos = 0;
for (Segment axSeg : axonSec.getSegments()) {
if (axSeg.getId() == synapse.getNeuron1AxSegment().getId()) {
break;
}
axSegPos++;
}
ax_soma_dist += ((float) axSegPos) / (axonSec.getSegments().size()) * axonSec.getLength();
synapse.setDendriticSomaDistance(ax_soma_dist);
//logger.info("dendritic_soma_distance(neuron1): " + iter.dendritic_soma_distance);
float denSomaDist = 0.0f;
Section denSec = synapse.getNeuron2DenSection();
if (denSec != null) {
if (denSec.getParentalLink() != null) {
denSomaDist = denSec.getParentalLink().getPolySomaDist();
//logger.info("den_soma_dist: " + den_soma_dist);
}
/*
logger.info("sec id: " + iter.neuron2_den_sectionId);
logger.info("number of segments: " + sec.getSegments().size());
logger.info("sec name: " + sec.getSectionName());
logger.info("sec length: " + sec.getLength());
*/
float secLength = denSec.getLength();
int nsegs = denSec.getSegments().size();
int segNum = 0;
for (Segment denSeg : denSec.getSegments()) {
if (denSeg.getId() == synapse.getNeuron2DenSectionSegment().getId()) {
break;
}
segNum++;
}
denSomaDist += ((float) segNum) / nsegs * secLength;
synapse.setDendriticSomaDistance(denSomaDist);
//logger.info("dendritic_soma_distance(neuron2): " + iter.dendritic_soma_distance + "\n");
}
}
/**
* Function to generate non-functional synapses on dendrite trees of neurons.
* Returns number of input synapses generated.
*/
@Override
public int createNonFunSynapses() {
int nsyn = 0;
for (Neuron neuron : neuronList) {
nsyn += createNonFunDendriticSynapses(synapseList, neuron);
logger.debug("synapses for " + neuron.getIndex() + "th neuron generated");
}
nsynapse += nsyn;
nnf_synapses += nsyn;
return nsyn;
}
/**
* A function to generate non-functional dendritic synapses for this neuron.
* It saves synapses in nf_synapses and Net::synapse_list
* Probability to have a synapse in a Segment is here =
* length of Segment * density value given by Param.neu.
* @param synapse_list is the net list to save synapses into
* @param i index of this neuron in the net.
* Returns number of nf-synapses.
* Apical dendrites have to be saved at the beginning of neurons
* dendrite list !!!!!!!!!!!!!!!! (TODO: Mark apical dendrites!)
*/
public int createNonFunDendriticSynapses(List<Cons> synapse_list, Neuron neuron) {
//logger.info("synapse_list size before: " + synapse_list.size());
//get minmax distances to soma as treshold
float den_bas = neuron.getParam().getDendriteParam().getNonFunctionalSynapses().getSimpleDistr().getDensity();
//logger.info("den_bas: " + den_bas);
float somaDistMinBas = neuron.getParam().getDendriteParam().getNonFunctionalSynapses().getSimpleDistr().getSomaDistance().getMin();
float somaDistMaxBas = neuron.getParam().getDendriteParam().getNonFunctionalSynapses().getSimpleDistr().getSomaDistance().getMax();
float somaDistMinApi = 0.0f;
float somaDistMaxApi = 0.0f;
float den_api = 1000.0f;
int napiden = neuron.getParam().getNumberOfApicalDendrites();
//logger.info("number of apical dendrites: " + napiden);
if (napiden != 0 && neuron.getParam().getApicalParam() != null) {
den_api = neuron.getParam().getApicalParam().getNonFunctionalSynapses().getSimpleDistr().getDensity();
somaDistMinApi = neuron.getParam().getApicalParam().getNonFunctionalSynapses().getSimpleDistr().getSomaDistance().getMin();
somaDistMaxApi = neuron.getParam().getApicalParam().getNonFunctionalSynapses().getSimpleDistr().getSomaDistance().getMax();
}
int nbasden = neuron.getParam().getNumberOfDendrites() - napiden;
int nden = nbasden + napiden;
int i;
float clen;
int ret = 0;
/*
for (int f = 0; f < dist_api.size(); f++) {
logger.info("dist_api: " + dist_api.get(f));
}
*/
/*
logger.info("den_bas: " + den_bas);
logger.info("den_api: " + den_api);
logger.info("napiden: " + napiden);
logger.info("nbasden: " + nbasden);
*/
for (i = 0; i < napiden; ++i) {
Section denSec;
Section.Iterator secit = neuron.getDendrites().get(i).getFirstSection().getIterator();
///< loop over all section of dendrite j of neuron2
while (secit.hasNext()) {
denSec = secit.next();
// segmentl_size = denSec.getSegments().size();
//logger.info("sec name: " + sec.getSectionName());
//logger.info("segment1_size: " + segmentl_size);
for (Segment denSeg : denSec.getSegments()) {
clen = denSeg.getLength();
float distToSoma = denSeg.getDistToSoma();
// logger.info("distToSoma: " + distToSoma);
float randNum = drawNumber.fdraw();
float bla = clen * den_api;
//logger.info("randNum: " + randNum);
/*
if(segmentl_size == 111 && sec.getSectionName().equals("dendrite: 595")) {
logger.info("clen: " + clen);
logger.info("den_api: " + den_api);
logger.info("neuron param fullKey: " + neuronParam.fullKey().toString());
logger.info("bla: " + bla);
logger.info("randNum: " + randNum);
logger.info("distToSoma > (dist_api).get(0): " + distToSoma + " > " + (dist_api).get(0));
logger.info("distToSoma > (dist_api).get(1): " + distToSoma + " < " + (dist_api).get(1));
}
*/
if (randNum < bla && distToSoma > somaDistMinApi && distToSoma < somaDistMaxApi) {
//logger.info("add cons to synapse list (first loop)!");
/*
logger.info("randNum: " + randNum);
logger.info("bla: " + bla);
logger.info("distToSoma > (dist_api).get(0): " + distToSoma + " > " + (dist_api).get(0));
logger.info("distToSoma > (dist_api).get(1): " + distToSoma + " < " + (dist_api).get(1));
*/
//synapse_list.add(new Cons(-1, k, null, null, i, denSec, j));
Cons syn = new Cons.Builder(null, denSeg).neuron2(neuron).neuron2DenSection(denSec).build();
synapse_list.add(syn);
denSeg.has_nf_synapse(true);
++ret;
}
}
}
}
//logger.info("ret after first loop: " + ret);
for (i = napiden; i < nden; ++i) {
Section denSec;
Section.Iterator secit = neuron.getDendrites().get(i).getFirstSection().getIterator();
///< loop over all section of dendrite j of neuron2
while (secit.hasNext()) {
denSec = secit.next();
for (Segment denSeg : denSec.getSegments()) {
float randNum = drawNumber.fdraw();
clen = denSeg.getLength();
float bla = clen * den_bas;
float distToSoma = denSeg.getDistToSoma();
if (randNum < bla && distToSoma > somaDistMinBas && distToSoma < somaDistMaxBas) {
//logger.info("add cons to synapse list (second loop)!");
Cons syn = new Cons.Builder(null, denSeg).neuron2(neuron).neuron2DenSection(denSec).build();
synapse_list.add(syn);
denSeg.has_nf_synapse(true);
++ret;
}
}
}
}
//logger.info("ret after second for loop: " + ret);
//logger.info("synapse_list size after: " + synapse_list.size());
// Set polygonal distance estimations.
int synListSize = 0;
if (synapse_list.size() > 0) {
synListSize = synapse_list.size() - 1;
}
for (int ii = 0; ii < ret; ii++) {
float den_soma_dist = 0;
int idx = synListSize - ii;
Cons co = synapse_list.get(idx);
/*
logger.info("denList.size:" + denList.size());
logger.info("co.neuron1_idx" + co.neuron1_idx);
logger.info("co.neuron2_idx" + co.neuron2_idx);
logger.info("co.neuron2_den_dix: " + co.neuron2_den_idx);
*/
Section denSec = co.getNeuron2DenSection();
if (denSec != null) {
if (denSec.getParentalLink() != null) {
den_soma_dist = denSec.getParentalLink().getPolySomaDist();
}
float secLength = denSec.getLength();
int nsegs = denSec.getSegments().size();
int segNum = 0;
for (Segment denSeg : denSec.getSegments()) {
if (denSeg.getId() == co.getNeuron2DenSectionSegment().getId()) {
break;
}
segNum++;
}
//den_soma_dist += ((float) iter.neuron2_den_section_segment_idx) / (sec.getSegments().size()) * sec.getLength();
den_soma_dist += ((float) segNum) / nsegs * secLength;
co.setDendriticSomaDistance(den_soma_dist);
}
}
//String mes = "non-functional synapses: " + ret;
//logger.info(mes);
return ret;
}
/** Get number of synapses of net. */
@Override
public int getNumSynapse() {
if (nsynapse != synapseList.size()) {
logger.debug("synapse list size is different of nsynapse! ");
logger.debug("nsynapse = " + nsynapse + " synapse list size = " + synapseList.size());
}
return nsynapse;
}
@Override
public int getNumNonFunSynapses() {
return nnf_synapses;
}
}