use of cbit.vcell.model.ReactionRule in project vcell by virtualcell.
the class MolecularComponentLargeShape method setComponentColor.
private Color setComponentColor() {
boolean highlight = isHighlighted();
if (owner == null) {
return highlight == true ? componentBad.brighter() : componentBad;
}
Color componentColor = highlight == true ? componentBad.brighter() : componentBad;
if (owner instanceof MolecularType) {
componentColor = highlight == true ? componentPaleYellow.brighter() : componentPaleYellow;
} else if (owner instanceof SpeciesContext) {
if (shapePanel != null && !shapePanel.isShowNonTrivialOnly()) {
componentColor = componentHidden;
} else {
componentColor = highlight == true ? componentPaleYellow.brighter() : componentPaleYellow;
}
} else if (mcp != null && owner instanceof RbmObservable) {
if (shapePanel != null && !shapePanel.isEditable()) {
componentColor = componentHidden;
} else {
componentColor = highlight == true ? componentHidden.brighter() : componentHidden;
}
if (mcp.getBondType() != BondType.Possible) {
componentColor = highlight == true ? componentPaleYellow.brighter() : componentPaleYellow;
}
} else if (owner instanceof ReactionRule) {
ReactionRule reactionRule = (ReactionRule) owner;
if (shapePanel.getDisplayMode() == DisplayMode.participantSignatures) {
componentColor = componentHidden;
if (shapePanel.isShowNonTrivialOnly() == true) {
if (mcp.getBondType() != BondType.Possible) {
componentColor = componentPaleYellow;
} else {
componentColor = componentHidden;
}
}
if (shapePanel.isShowDifferencesOnly()) {
switch(shapePanel.hasBondChanged(reactionRule.getName(), mcp)) {
case CHANGED:
componentColor = Color.orange;
break;
case ANALYSISFAILED:
ArrayList<Issue> issueList = new ArrayList<Issue>();
reactionRule.gatherIssues(new IssueContext(), issueList);
boolean bRuleHasErrorIssues = false;
for (Issue issue : issueList) {
if (issue.getSeverity() == Severity.ERROR) {
bRuleHasErrorIssues = true;
break;
}
}
if (bRuleHasErrorIssues) {
componentColor = componentHidden;
} else {
System.err.println("ReactionRule Analysis failed, but there are not Error Issues with ReactionRule " + reactionRule.getName());
componentColor = Color.red.darker();
}
break;
default:
break;
}
}
} else if (shapePanel.getDisplayMode() == DisplayMode.rules) {
componentColor = componentHidden;
if (shapePanel.isShowNonTrivialOnly() == true) {
if (mcp.getBondType() != BondType.Possible) {
componentColor = componentPaleYellow;
} else {
componentColor = componentHidden;
}
}
if (shapePanel.isShowDifferencesOnly()) {
switch(shapePanel.hasBondChanged(mcp)) {
case CHANGED:
componentColor = Color.orange;
break;
case ANALYSISFAILED:
ArrayList<Issue> issueList = new ArrayList<Issue>();
reactionRule.gatherIssues(new IssueContext(), issueList);
boolean bRuleHasErrorIssues = false;
for (Issue issue : issueList) {
if (issue.getSeverity() == Severity.ERROR) {
bRuleHasErrorIssues = true;
break;
}
}
if (bRuleHasErrorIssues) {
componentColor = componentHidden;
} else {
System.err.println("ReactionRule Analysis failed, but there are not Error Issues with ReactionRule " + reactionRule.getName());
componentColor = Color.red.darker();
}
break;
default:
break;
}
}
} else {
componentColor = highlight == true ? componentHidden.brighter() : componentHidden;
if (mcp.getBondType() != BondType.Possible) {
componentColor = highlight == true ? componentPaleYellow.brighter() : componentPaleYellow;
}
}
}
if (hasErrorIssues(owner, mcp, mc)) {
componentColor = highlight == true ? componentBad.brighter() : componentBad;
}
return componentColor;
}
use of cbit.vcell.model.ReactionRule in project vcell by virtualcell.
the class MolecularTypeLargeShape method paintSpecies.
// --------------------------------------------------------------------------------------
private void paintSpecies(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Font fontOld = g2.getFont();
Color colorOld = g2.getColor();
Stroke strokeOld = g2.getStroke();
Color primaryColor = null;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (mt == null && mtp == null) {
// plain species context
Color exterior;
if (owner == null) {
// for plain species, we just draw a circle based on height!!! we ignore width!!!
// error
exterior = Color.red.darker();
} else {
if (!shapePanel.isShowMoleculeColor()) {
exterior = Color.GRAY;
} else {
// plain species
exterior = Color.green.darker().darker();
}
}
Point2D center = new Point2D.Float(xPos + baseHeight / 3, yPos + baseHeight / 3);
float radius = baseHeight * 0.5f;
Point2D focus = new Point2D.Float(xPos + baseHeight / 3 - 1, yPos + baseHeight / 3 - 1);
float[] dist = { 0.1f, 1.0f };
Color[] colors = { Color.white, exterior };
RadialGradientPaint p = new RadialGradientPaint(center, radius, focus, dist, colors, CycleMethod.NO_CYCLE);
g2.setPaint(p);
Ellipse2D circle = new Ellipse2D.Double(xPos, yPos, baseHeight, baseHeight);
g2.fill(circle);
Ellipse2D circle2 = new Ellipse2D.Double(xPos - 1, yPos - 1, baseHeight + 0.7, baseHeight + 0.7);
g2.setPaint(getDefaultColor(Color.DARK_GRAY));
int z = shapePanel.getZoomFactor();
g2.setStroke(new BasicStroke(2.0f + 0.14f * z));
g2.draw(circle2);
if (owner == null) {
Font font = fontOld.deriveFont(Font.BOLD);
g.setFont(font);
g.setColor(Color.red.darker().darker());
g2.drawString("Error parsing generated species!", xPos + baseHeight + 10, yPos + baseHeight - 9);
}
g2.setFont(fontOld);
g2.setColor(colorOld);
g2.setStroke(strokeOld);
return;
} else {
// molecular type, species pattern, observable
if (mt == null || mt.getModel() == null) {
primaryColor = Color.blue.darker().darker();
} else {
if (shapePanel.getDisplayMode() == DisplayMode.participantSignatures) {
if (!shapePanel.isShowMoleculeColor()) {
primaryColor = AbstractComponentShape.componentVeryLightGray;
} else {
RbmModelContainer rbmmc = mt.getModel().getRbmModelContainer();
List<MolecularType> mtList = rbmmc.getMolecularTypeList();
int index = mtList.indexOf(mt);
index = index % 7;
primaryColor = colorTable[index].darker().darker();
}
if (shapePanel.isShowDifferencesOnly()) {
ReactionRule reactionRule = (ReactionRule) owner;
switch(shapePanel.hasNoMatch(reactionRule.getName(), mtp)) {
case CHANGED:
primaryColor = AbstractComponentShape.deepOrange;
break;
case // keep whatever color we set above
UNCHANGED:
break;
case ANALYSISFAILED:
ArrayList<Issue> issueList = new ArrayList<Issue>();
reactionRule.gatherIssues(new IssueContext(), issueList);
boolean bRuleHasErrorIssues = false;
for (Issue issue : issueList) {
if (issue.getSeverity() == Severity.ERROR) {
bRuleHasErrorIssues = true;
break;
}
}
if (bRuleHasErrorIssues) {
primaryColor = AbstractComponentShape.componentHidden;
} else {
System.err.println("ReactionRule Analysis failed, but there are not Error Issues with ReactionRule " + reactionRule.getName());
primaryColor = Color.red.darker();
}
break;
default:
break;
}
}
} else if (shapePanel.getDisplayMode() == DisplayMode.rules) {
if (!shapePanel.isShowMoleculeColor()) {
primaryColor = AbstractComponentShape.componentVeryLightGray;
} else {
RbmModelContainer rbmmc = mt.getModel().getRbmModelContainer();
List<MolecularType> mtList = rbmmc.getMolecularTypeList();
int index = mtList.indexOf(mt);
index = index % 7;
primaryColor = colorTable[index].darker().darker();
}
// if we show difference, we apply that now and override the color
if (shapePanel.isShowDifferencesOnly()) {
ReactionRule reactionRule = (ReactionRule) owner;
switch(shapePanel.hasNoMatch(mtp)) {
case CHANGED:
primaryColor = AbstractComponentShape.deepOrange;
break;
case // keep whatever color we set above
UNCHANGED:
break;
case ANALYSISFAILED:
ArrayList<Issue> issueList = new ArrayList<Issue>();
reactionRule.gatherIssues(new IssueContext(), issueList);
boolean bRuleHasErrorIssues = false;
for (Issue issue : issueList) {
if (issue.getSeverity() == Severity.ERROR) {
bRuleHasErrorIssues = true;
break;
}
}
if (bRuleHasErrorIssues) {
primaryColor = AbstractComponentShape.componentHidden;
} else {
System.err.println("ReactionRule Analysis failed, but there are not Error Issues with ReactionRule " + reactionRule.getName());
primaryColor = Color.red.darker();
}
break;
default:
break;
}
}
} else {
// TODO: do we ever get here legitimately? if not throw an exception!
RbmModelContainer rbmmc = mt.getModel().getRbmModelContainer();
List<MolecularType> mtList = rbmmc.getMolecularTypeList();
int index = mtList.indexOf(mt);
index = index % 7;
if (!shapePanel.isShowMoleculeColor()) {
primaryColor = AbstractComponentShape.componentVeryLightGray;
} else {
primaryColor = isHighlighted() == true ? Color.white : colorTable[index].darker().darker();
}
if (hasErrorIssues(owner, mt)) {
primaryColor = isHighlighted() ? Color.white : Color.red;
}
}
}
}
// paint the structure contour if applicable (only for anchored molecules!)
if (structure != null && mt != null && !mt.isAnchorAll() && mt.getAnchors().size() > 0) {
paintNarrowCompartmentRight(g);
} else if (owner instanceof MolecularType && !mt.isAnchorAll()) {
paintNarrowCompartmentRight(g);
}
// paint the shape of the molecule and fill it with color
GradientPaint p = new GradientPaint(xPos, yPos, primaryColor, xPos, yPos + baseHeight / 2, Color.WHITE, true);
g2.setPaint(p);
RoundRectangle2D rect = new RoundRectangle2D.Float(xPos, yPos, width, baseHeight, cornerArc, cornerArc);
g2.fill(rect);
RoundRectangle2D inner = new RoundRectangle2D.Float(xPos + 1, yPos + 1, width - 2, baseHeight - 2, cornerArc - 3, cornerArc - 3);
if (isHighlighted()) {
if (hasErrorIssues(owner, mt)) {
g2.setPaint(Color.red);
} else {
g2.setPaint(getDefaultColor(Color.BLACK));
}
g2.draw(inner);
if (hasErrorIssues(owner, mt)) {
g2.setPaint(Color.red);
} else {
g2.setPaint(getDefaultColor(Color.BLACK));
}
g2.draw(rect);
} else {
if (hasErrorIssues(owner, mt)) {
g2.setPaint(Color.red.darker());
} else {
g2.setPaint(getDefaultColor(Color.GRAY));
}
g2.draw(inner);
if (hasErrorIssues(owner, mt)) {
g2.setPaint(Color.red.darker());
} else {
g2.setPaint(getDefaultColor(Color.DARK_GRAY));
}
g2.draw(rect);
}
// paint the anchor glyph
Rectangle r = getAnchorHotspot();
if (r != null) {
// g2.drawRect(r.x, r.y, r.width, r.height); // anchor tooltip hotspot area
int z = shapePanel.getZoomFactor();
int w = r.width;
int x = r.x + w / 2;
int y = r.y;
int h = 12 + z / 2;
h = z < -2 ? h - 1 : h;
h = z < -4 ? h - 1 : h;
Line2D line = new Line2D.Float(x, y, x, y + h);
g2.setPaint(getDefaultColor(Color.RED.darker().darker()));
g2.setStroke(new BasicStroke(2.6f + 0.13f * z));
g2.draw(line);
// TODO: adjust the arc at deep zoom!
double a1 = z < -3 ? 245 : 240;
// 60
double a2 = z < -3 ? 52 : 59;
Arc2D arc = new Arc2D.Double(x - h, y - h, 2 * h, 2 * h, a1, a2, Arc2D.OPEN);
g2.setStroke(new BasicStroke(2.6f + 0.20f * z));
g2.draw(arc);
g2.setPaint(colorOld);
g2.setStroke(strokeOld);
}
// the text inside the molecule shape
if (mt == null && mtp == null) {
// plain species context
// don't write any text inside
} else {
// molecular type, species pattern
Graphics gc = shapePanel.getGraphics();
Font font = deriveMoleculeFontBold(g, shapePanel);
g.setFont(font);
// font color
g.setColor(getDefaultColor(Color.BLACK));
int fontSize = font.getSize();
int textX = xPos + 11;
int textY = yPos + baseHeight - (baseHeight - fontSize) / 2;
g2.drawString(name, textX, textY);
if (owner instanceof ReactionRule && mtp != null && mtp.hasExplicitParticipantMatch()) {
int z = shapePanel.getZoomFactor();
if (z >= LargeShapeCanvas.SmallestZoomFactorWithText) {
// hide the matching too when we don't display the name
FontMetrics fm = gc.getFontMetrics(font);
int stringWidth = fm.stringWidth(name);
Font smallerFont = font.deriveFont(font.getSize() * 0.8F);
g.setFont(smallerFont);
g2.drawString(mtp.getParticipantMatchLabel(), textX + stringWidth + 2, textY + 2);
}
}
}
g.setFont(fontOld);
g.setColor(colorOld);
g2.setStroke(strokeOld);
for (MolecularComponentLargeShape mcls : componentShapes) {
// paint the components
mcls.paintSelf(g);
}
g2.setFont(fontOld);
g2.setColor(colorOld);
g2.setStroke(strokeOld);
}
use of cbit.vcell.model.ReactionRule in project vcell by virtualcell.
the class SpeciesPatternLargeShape method getStructure.
public Structure getStructure() {
Structure structure = null;
if (owner instanceof ReactionRule) {
ReactionRule rr = (ReactionRule) owner;
ReactantPattern rp = rr.getReactantPattern(sp);
ProductPattern pp = rr.getProductPattern(sp);
if (rp != null) {
structure = rp.getStructure();
} else if (pp != null) {
structure = pp.getStructure();
} else {
structure = ((ReactionRule) owner).getStructure();
}
} else if (owner instanceof SpeciesContext && ((SpeciesContext) owner).hasSpeciesPattern()) {
structure = ((SpeciesContext) owner).getStructure();
} else if (owner instanceof RbmObservable) {
structure = ((RbmObservable) owner).getStructure();
}
return structure;
}
use of cbit.vcell.model.ReactionRule in project vcell by virtualcell.
the class SpeciesPatternLargeShape method paintSelf.
public void paintSelf(Graphics g, boolean bPaintContour) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (shapePanel.getDisplayMode() == DisplayMode.participantSignatures) {
if (bMatchesSignature == true) {
paintMatchesSignatureContour(g);
}
} else if (bPaintContour && (owner instanceof RbmObservable || owner instanceof ReactionRule)) {
paintContour(g);
}
// TODO: bring this back once we add compartments to species patterns
paintCompartment(g);
if (speciesShapes.isEmpty()) {
// paint empty dummy
MolecularTypeLargeShape.paintDummy(g, xPos, yPos, shapePanel);
}
for (MolecularTypeLargeShape stls : speciesShapes) {
stls.paintSelf(g);
}
if (owner instanceof RbmObservable) {
// endText = "Right click here to add a molecule.";
endText = "";
}
// // matches between molecular types - only within reaction rules
// if(owner instanceof ReactionRule) {
// Color colorOld = g2.getColor();
// Font fontOld = g.getFont();
//
// Font font = MolecularComponentLargeShape.deriveComponentFontBold(graphicsContext);
// Color fontColor = Color.gray;
// Color lineColor = Color.lightGray;
// g2.setFont(font);
// g2.setColor(fontColor);
// for(MolecularTypeLargeShape mtls : speciesShapes) {
// MolecularTypePattern mtp = mtls.getMolecularTypePattern();
// if(!mtp.hasExplicitParticipantMatch()) {
// continue; // nothing to do if no explicit match
// }
// int x = mtls.getX()+10;
// int y = mtls.getY()-7;
// if(((ReactionRule)owner).isReactant(sp)) {
// g2.drawLine(x, y, x, y+6); // vertical line
// g2.drawLine(x+1, y, x+1, y+6);
//
// g2.drawLine(x, y, x+10, y); // line to right
// g2.drawLine(x, y+1, x+10, y+1);
//
// g2.drawString(mtp.getParticipantMatchLabel(), x+12, y+4);
// } else {
// g2.drawLine(x, y, x, y+6);
// g2.drawLine(x+1, y, x+1, y+6);
//
// g2.drawLine(x, y, x-10, y); // line to left
// g2.drawLine(x, y+1, x-10, y+1);
//
// g2.drawString(mtp.getParticipantMatchLabel(), x+3, y+4); // the match label
// }
// }
// g2.setFont(fontOld);
// g2.setColor(colorOld);
// }
// --- ------- Bonds between components ------------------------------------------------------------------------
// initial height of vertical bar of matched bond
int yDouble = 18;
if (shapePanel != null) {
// arbitrary factor, to be determined
int Ratio = 1;
// negative if going smaller
int zoomFactor = shapePanel.getZoomFactor() * Ratio;
yDouble += zoomFactor;
}
// distance between 2 vertical line segments of "exists" bond
int yExists = 5;
// separation between 2 vertical line segments of "exists" bond
int ysExists = 3;
if (shapePanel != null) {
// negative if going smaller
double zoomFactor = (double) (shapePanel.getZoomFactor()) / 3.0;
yExists += (int) zoomFactor;
ysExists += (int) zoomFactor;
}
// bond related attributes
// offset of the bond id - we assume there will never be more than 99
final int xOneLetterOffset = 7;
final int xTwoLetterOffset = 13;
// default y distance between 2 adjacent bars
int separ = 5;
for (int i = 0; i < bondSingles.size(); i++) {
BondSingle bs = bondSingles.get(i);
Color colorOld = g2.getColor();
Font fontOld = g.getFont();
Color fontColor = Color.red;
Color lineColor = Color.red;
if (AbstractComponentShape.isHidden(owner, bs.mcp)) {
fontColor = getDefaultColor(Color.gray);
lineColor = getDefaultColor(Color.lightGray);
} else {
fontColor = getDefaultColor(Color.black);
lineColor = getDefaultColor(Color.gray);
}
if (bs.mcp.getBondType().equals(BondType.Possible)) {
// ? (Possible)
Graphics gc = shapePanel.getGraphics();
if (shapePanel.getZoomFactor() >= LargeShapeCanvas.SmallestZoomFactorWithText) {
Font font = MolecularComponentLargeShape.deriveComponentFontBold(gc, shapePanel);
g2.setFont(font);
g2.setColor(fontColor);
g2.drawString(bs.mcp.getBondType().symbol, bs.from.x - xOneLetterOffset, bs.from.y + yLetterOffset);
}
g2.setColor(lineColor);
g2.drawLine(bs.from.x, bs.from.y, bs.from.x, bs.from.y + ysExists);
g2.setColor(getDefaultColor(Color.gray));
g2.drawLine(bs.from.x + 1, bs.from.y, bs.from.x + 1, bs.from.y + ysExists);
g2.setColor(lineColor);
g2.drawLine(bs.from.x, bs.from.y + yExists, bs.from.x, bs.from.y + yExists + ysExists);
g2.setColor(getDefaultColor(Color.gray));
g2.drawLine(bs.from.x + 1, bs.from.y + yExists, bs.from.x + 1, bs.from.y + yExists + ysExists);
g2.setColor(lineColor);
g2.drawLine(bs.from.x, bs.from.y + yExists * 2, bs.from.x, bs.from.y + yExists * 2 + ysExists);
g2.setColor(getDefaultColor(Color.gray));
g2.drawLine(bs.from.x + 1, bs.from.y + yExists * 2, bs.from.x + 1, bs.from.y + yExists * 2 + ysExists);
} else if (bs.mcp.getBondType().equals(BondType.Exists)) {
// g2.setColor(plusSignGreen); // draw a green '+' sign
// g2.drawLine(bs.from.x-8, bs.from.y+6, bs.from.x-3, bs.from.y+6); // horizontal
// g2.drawLine(bs.from.x-8, bs.from.y+7, bs.from.x-3, bs.from.y+7);
// g2.drawLine(bs.from.x-6, bs.from.y+4, bs.from.x-6, bs.from.y+9); // vertical
// g2.drawLine(bs.from.x-5, bs.from.y+4, bs.from.x-5, bs.from.y+9);
g2.setColor(lineColor);
g2.drawLine(bs.from.x, bs.from.y, bs.from.x, bs.from.y + yExists * 2 + ysExists);
g2.setColor(getDefaultColor(Color.gray));
g2.drawLine(bs.from.x + 1, bs.from.y, bs.from.x + 1, bs.from.y + yExists * 2 + ysExists);
} else {
// g2.setColor(Color.red.darker()); // draw a dark red '-' sign
// g2.drawLine(bs.from.x-10, bs.from.y+5, bs.from.x-4, bs.from.y+5); // horizontal
// g2.drawLine(bs.from.x-10, bs.from.y+6, bs.from.x-4, bs.from.y+6);
// g2.drawLine(bs.from.x-6, bs.from.y+4, bs.from.x-6, bs.from.y+9); // vertical
// g2.drawLine(bs.from.x-5, bs.from.y+4, bs.from.x-5, bs.from.y+9);
// for BondType.None we show nothing at all
// below small black vertical line ended in a red "x" (comment out if not wanted)
// g2.setColor(lineColor);
// g2.drawLine(bs.from.x, bs.from.y, bs.from.x, bs.from.y+7);
// g2.setColor(Color.gray);
// g2.drawLine(bs.from.x+1, bs.from.y, bs.from.x+1, bs.from.y+7);
//
// int vo = 8;
// g2.setColor(Color.red);
// g2.drawLine(bs.from.x-3, bs.from.y+2+vo, bs.from.x+4, bs.from.y-2+vo);
// g2.setColor(Color.gray);
// g2.drawLine(bs.from.x-3, bs.from.y+3+vo, bs.from.x+4, bs.from.y-1+vo);
//
// g2.setColor(Color.red);
// g2.drawLine(bs.from.x-3, bs.from.y-2+vo, bs.from.x+4, bs.from.y+2+vo);
// g2.setColor(Color.gray);
// g2.drawLine(bs.from.x-3, bs.from.y-1+vo, bs.from.x+4, bs.from.y+3+vo);
// below small black vertical line (comment out if not wanted)
// int vo = 10;
// g2.setColor(lineColor);
// g2.drawLine(bs.from.x, bs.from.y, bs.from.x, bs.from.y+vo);
// g2.setColor(Color.gray);
// g2.drawLine(bs.from.x+1, bs.from.y, bs.from.x+1, bs.from.y+vo);
//
// small horizontal red line at the end of the vertical one
// g2.setColor(Color.gray);
// g2.drawLine(bs.from.x-1, bs.from.y+vo-1, bs.from.x+2, bs.from.y+vo-1);
// g2.setColor(Color.gray);
// g2.drawLine(bs.from.x-1, bs.from.y+vo, bs.from.x+2, bs.from.y+vo);
}
g.setFont(fontOld);
g2.setColor(colorOld);
}
switch(// variable distance on y between bonds, we draw them closer when there are many of them
bondPairs.size()) {
case 1:
case 2:
separ = 5;
break;
case 3:
case 4:
separ = 4;
break;
case 5:
case 6:
separ = 3;
break;
case 7:
case 8:
case 9:
separ = 2;
break;
default:
separ = 1;
}
for (int i = 0; i < bondPairs.size(); i++) {
BondPair bp = bondPairs.get(i);
Color colorOld = g2.getColor();
Font fontOld = g.getFont();
if (shapePanel.isShowDifferencesOnly()) {
g2.setColor(getDefaultColor(Color.gray));
} else {
g2.setColor(getDefaultColor(GraphConstants.bondHtmlColors[bp.id % GraphConstants.bondHtmlColors.length]));
}
g2.drawLine(bp.from.x, bp.from.y, bp.from.x, bp.from.y + yDouble + i * separ);
g2.drawLine(bp.to.x, bp.to.y, bp.to.x, bp.to.y + yDouble + i * separ);
g2.drawLine(bp.from.x, bp.from.y + yDouble + i * separ, bp.to.x, bp.to.y + yDouble + i * separ);
Graphics gc = shapePanel.getGraphics();
if (shapePanel.getZoomFactor() >= LargeShapeCanvas.SmallestZoomFactorWithText) {
Font font = MolecularComponentLargeShape.deriveComponentFontBold(gc, shapePanel);
g.setFont(font);
String nr = bp.id + "";
if (nr.length() < 2) {
g2.drawString(nr, bp.from.x - xOneLetterOffset, bp.from.y + yLetterOffset);
g2.drawString(nr, bp.to.x - xOneLetterOffset, bp.to.y + yLetterOffset);
} else {
g2.drawString(nr, bp.from.x - xTwoLetterOffset, bp.from.y + yLetterOffset);
g2.drawString(nr, bp.to.x - xTwoLetterOffset, bp.to.y + yLetterOffset);
}
}
g2.setColor(getDefaultColor(Color.lightGray));
g2.drawLine(bp.from.x + 1, bp.from.y + 1, bp.from.x + 1, bp.from.y + yDouble + i * separ);
g2.drawLine(bp.to.x + 1, bp.to.y + 1, bp.to.x + 1, bp.to.y + yDouble + i * separ);
g2.drawLine(bp.from.x, bp.from.y + yDouble + i * separ + 1, bp.to.x + 1, bp.to.y + yDouble + i * separ + 1);
g.setFont(fontOld);
g2.setColor(colorOld);
}
if (!endText.isEmpty()) {
Color colorOld = g2.getColor();
g2.setColor(getDefaultColor(Color.black));
g.drawString(endText, getRightEnd() + 20, yPos + 20);
g2.setColor(colorOld);
}
}
use of cbit.vcell.model.ReactionRule in project vcell by virtualcell.
the class BNGExecutorServiceMultipass method doWork.
private CorrectedSR doWork(String oldSpeciesString, String newNetFile) throws ParseException {
// TODO: make a map to preserve the ancestry of each generated species (rule and iteration that generated it)
// each species may be generated multiple times, by different rules, at different iterations
// the key should be the normalized (sorted lexicographically) expression of each species
// parse the .net file with BNGOutputFileParser
// seed species at the beginning of the current iteration
List<BNGSpecies> oldSpeciesList = BNGOutputFileParser.createBngSpeciesOutputSpec(oldSpeciesString);
// same as above, used internally, as we add new species from the current iteration we put them here;
// used to speed up the verifications and reduce the isomorphism calls together with the isomorphismSignaturesMap
Map<String, BNGSpecies> seedSpeciesMap = BNGOutputFileParser.createBngSpeciesSignatureMap(oldSpeciesString);
// .net file content generated during current iteration
BNGOutputSpec workSpec = BNGOutputFileParser.createBngOutputSpec(newNetFile);
// we build here the list of valid (perhaps even corrected) NEW species
List<BNGSpecies> newSpeciesList = new ArrayList<>();
// we build here the list of flattened reactions (corrected at need, if the species were corrected)
ArrayList<BNGReaction> newReactionsList = new ArrayList<BNGReaction>(Arrays.asList(workSpec.getBNGReactions()));
// ArrayList<ObservableGroup> newObservablesList = new ArrayList<ObservableGroup>(); // here we put all the observables after correction
// ArrayList<ObservableGroup> newObservablesList = new ArrayList<ObservableGroup>(Arrays.asList(workSpec.getObservableGroups()));
// identify new products, loop thorough each of them
Pair<List<BNGSpecies>, List<BNGSpecies>> p = BNGSpecies.diff(oldSpeciesList, workSpec.getBNGSpecies());
List<BNGSpecies> removed = p.one;
// after possible needed corrections we may end up with more or less new species for this iteration
List<BNGSpecies> added = p.two;
if (!removed.isEmpty()) {
// this may actually be fired if the BNGSpecies.equals() fails for some reason
throw new RuntimeException("No existing BNGSpecies may be removed: \n" + removed.get(0));
}
if (added.isEmpty()) {
System.out.println("No new species added this iteration. Finished!");
}
// in this map we store which of the indexes of species generated during the current iteration
// were converted into what after correction
// an index may exist already in which case we won't save a duplicate or the same new species (that needs repair)
// may result in more new species after being fixed
// param1: original index of the newly created species before repairing it
// param2: list of the indexes of the species resulting from the original after repairing
Map<String, List<String>> indexesMap = new LinkedHashMap<>();
// some reactions may end up as identity reactions after corrections caused by anchoring
// for instance a transport xA -> yA may become xA -> xA after correction if A is anchored to x
// we make a list of these and get rid of them at the end
Set<BNGReaction> identityReactions = new HashSet<>();
// as we validate and we add new species, we use this index to set their network index
// we can't get the indexes given to the newly generated species for granted, during correction we may
// lose or gain species
int firstAvailableIndex = BNGOutputSpec.getFirstAvailableSpeciesIndex(oldSpeciesList);
int summaryCreated = added.size();
int summaryRepaired = 0;
int summaryExisted = 0;
// species we're adding at the end of this iteration, after repairing and checking for existing
int summarySpecies = 0;
for (BNGSpecies s : added) {
// find the flattened reaction and from the reaction find the rule it's coming from
for (BNGReaction r : newReactionsList) {
// console only message
String message = "";
// array list with position of this species in the product (may be more than 1)
List<Integer> reactionProductPositions = r.findProductPositions(s);
if (reactionProductPositions.isEmpty()) {
// this species is not a product of this reaction, nothing to do
continue;
}
String ruleName = r.getRuleName();
if (r.isRuleReversed()) {
throw new RuntimeException("Reaction " + ruleName + " cannot be 'reverse'.");
}
// System.out.println("Species " + s + " found in rule " + r.getRuleName() + ", at index " + position);
// check the product against the rule to see if it's valid
// sanity check: only "transport" rules can give incorrect products, any rule with all participants in the same
// compartment should only give valid products (is that so?)
String structureName;
if (model.getStructures().length == 1) {
structureName = model.getStructure(0).getName();
} else {
// this is the structure where the product should be, according to the rule
structureName = findRuleProductCompartment(s);
}
ReactionRule rr = model.getRbmModelContainer().getReactionRule(ruleName);
// TODO: the code below may be greatly simplified using the more advanced BNGSpecies classes instead of using the strings
// 'one' is the list of all the compartments mentioned in this product; for single compartment models 'one' will always be 1
// and thus we'll never attempt to correct anything
// 'two' is the BNGSpecies string with the compartment info extracted (that is, the AAA sites extracted)
Pair<List<String>, String> pair = RbmUtils.extractCompartment(s.getName());
boolean needsRepairing = false;
if (pair.one.size() > 1) {
// System.out.println(s.getName() + " multiple compartments, needs repairing.");
message += s.getName() + " needs repairing... ";
needsRepairing = true;
/* At this point we have the 'probable' structure of this product, extracted from the rule (structureName)
However, we need to verify against the lists of anchors to make sure is not excluded from the possible list of anchors
for any of the molecules and choose a compatible structure name, as follows:
compartments x y z
molecules A B C A comes as transport
rule says that this product belongs in x
cases:
1. A~y xB.xC.yA -> yB.yC.yA - can't use x as the rule says because A must be anchored to y and that takes precedence
- if B or C can't be in y throw exception, our anchors are too restrictive
2. A~x~y xB.xC.yA -> xB.xC.xA - correct to what the rule wants since x is acceptable as anchor for A
3. A~z xB.xC.yA -> !!! - impossible, there is no reactant such that A can get in y (throw exception)
4. A~x~z xB.xC.yA -> !!! - same as above
step 1. look for exceptions: make sets with the compartments for each molecule in the species and see if
they all are allowed by the anchor rules (if not, we are in cases 3 or 4 - throw exception
step 2. see if structureName is acceptable for all anchored molecules - if yes, use it
step 3. intersect all sets from step 1
3.1 - if there's 1 compartment that is acceptable for all, use it
3.2 - if there's no compartment then we can't put the species anywhere - throw exception
3.3 - if there's more than 1 compartment, it's ambiguous - throw exception
*/
// ex of one entry: key T, value mem, cyt
Map<String, Set<String>> speciesAnchorMap = extractSpeciesAnchorMap(s);
// sanity check, step 1
for (Map.Entry<String, Set<String>> entry : speciesAnchorMap.entrySet()) {
// molecule in the newly generated species (product)
String molecule = entry.getKey();
if (!anchorsMap.containsKey(molecule)) {
// this molecule can be anywhere, it's not anchored - nothing to verify
continue;
}
// 1 or more location where we try to put it (before correction may be more than 1)
Set<String> structures = entry.getValue();
// these structures MUST all be allowed by the anchor rule, otherwise it would mean they are coming from a reactant that cannot exist (case 3 or 4 above)
for (String wantedStructure : structures) {
Set<String> allowedStructures = anchorsMap.get(molecule);
if (!allowedStructures.contains(wantedStructure)) {
// should never happen: no reactant and no rule should have placed this molecule in this structure
throw new RuntimeException("Error in " + s.getName() + "\nMolecule " + molecule + " cannot possibly be in Structure " + wantedStructure);
}
}
}
// step 2
boolean isCandidateStructureAcceptable = true;
for (Map.Entry<String, Set<String>> entry : speciesAnchorMap.entrySet()) {
// molecule in the newly generated species (product)
String molecule = entry.getKey();
if (!anchorsMap.containsKey(molecule)) {
// this molecule can be anywhere, it's not anchored - nothing to verify
continue;
}
Set<String> allowedStructures = anchorsMap.get(molecule);
if (!allowedStructures.contains(structureName)) {
// the structure 'wanted' by the rule for this product is not acceptable because of some anchor rule
isCandidateStructureAcceptable = false;
break;
}
}
// step 3
if (isCandidateStructureAcceptable == false) {
// we try to find one and only one structure that would satisfy all anchored molecules of this species
TreeSet<String> intersection = new TreeSet<>();
for (Structure str : model.getStructures()) {
// we start by adding all structures in the model
intersection.add(str.getName());
}
for (Map.Entry<String, Set<String>> entry : speciesAnchorMap.entrySet()) {
// molecule in the newly generated species (product)
String molecule = entry.getKey();
if (!anchorsMap.containsKey(molecule)) {
// this molecule can be anywhere, it's not anchored - nothing to verify
continue;
}
// we already know from step 1 that all structures here are acceptable by the anchor
Set<String> structures = anchorsMap.get(molecule);
// intersection retains only the elements in 'structures'
intersection.retainAll(structures);
}
if (intersection.size() == 0) {
// no structure satisfies the anchor rules for the molecules in this species
throw new RuntimeException("Error in " + s.getName() + "\nThe Structures allowed for anchored molecules are mutually exclusive.");
} else if (intersection.size() > 1) {
// ambiguous, don't know which compartment to pick
throw new RuntimeException("Error in " + s.getName() + "\nMultiple Structures allowed by the anchor rules, don't know which to choose.");
} else {
// found one single structure everybody is happy about
structureName = intersection.first();
}
}
} else {
// no transport caused by a 'wild card', just direct rule application (no compartment ambiguity, nothing to correct)
String structure;
if (model.getStructures().length == 1) {
structure = model.getStructure(0).getName();
} else {
structure = pair.one.get(0);
}
if (!structure.equals(structureName)) {
// the rule (no transport caused by '?' is possible)
throw new RuntimeException("Error in " + s.getName() + "\nIf one single structure is present in the species it must match the structure of the rule product");
}
// product structure (from rule) should not conflict with the anchor - we should have error issue in the rule itself reporting the conflict
// TODO: check here too anyway, just in case?
}
// new generated species that we may add the list of species for the next iteration
BNGSpecies candidate;
// deleted or added previously during earlier iterations through newly created species
if (needsRepairing) {
// if not valid, correct the fake "compartment" site to be conform to the compartment of
// the product pattern
String speciesRepairedName = RbmUtils.repairCompartment(s.getName(), structureName);
speciesRepairedName = RbmUtils.resetProductIndex(speciesRepairedName);
candidate = new BNGComplexSpecies(speciesRepairedName, s.getConcentration(), firstAvailableIndex);
// System.out.println(candidate.getName() + " repaired!");
message += "repaired from rule " + rr.getDisplayName() + "... ";
summaryRepaired++;
System.out.println("");
} else {
String speciesName = s.getName();
speciesName = RbmUtils.resetProductIndex(speciesName);
candidate = new BNGComplexSpecies(speciesName, s.getConcentration(), firstAvailableIndex);
}
// At this point we have a valid candidate - but we may not need it if it already exist in the list of old seed species or in the list of
// new seed species we're building now (it may exist in either if correction took place)
//
// We correct the reaction to match the networkFileIndex of this species (useless activity except for the last iteration
// when we want the valid list of flattened reactions
//
// we set this to an existing species if the candidate matches it (directly or through isomorphism)
BNGSpecies existingMatch = null;
long st = System.currentTimeMillis();
String sig = BNGSpecies.getShortSignature(candidate, sigDetailLevel);
if (!shortSignaturesSet.contains(sig)) {
// our candidate has a new short signature, this means it is certainly not among the existing species
// no point in doing any other search to find it
} else {
// short signature match, now we check if the full species exists or is isomorphic with an existing one
String isomorphSpeciesName = isomorphismSignaturesMap.get(candidate.getName());
if (isomorphSpeciesName != null) {
// name of an existing species that is isomorphic with our candidate
// we recover the existing species and will use it instead of the candidate
existingMatch = seedSpeciesMap.get(isomorphSpeciesName);
if (existingMatch == null) {
throw new RuntimeException("Unable to find an isomorph BNGSpecies named " + isomorphSpeciesName + " that should have existed.");
}
} else {
// not present among the existing species or their known isomorphisms
// try to find an isomorphism the hard way
BNGSpecies existingMatchInNew = BNGOutputSpec.findMatch(candidate, newSpeciesList, sigDetailLevel);
if (existingMatchInNew != null) {
isomorphismSignaturesMap.put(candidate.getName(), existingMatchInNew.getName());
existingMatch = existingMatchInNew;
} else {
BNGSpecies existingMatchInOld = BNGOutputSpec.findMatch(candidate, oldSpeciesList, sigDetailLevel);
if (existingMatchInOld != null) {
isomorphismSignaturesMap.put(candidate.getName(), existingMatchInOld.getName());
existingMatch = existingMatchInOld;
}
}
}
}
long et = System.currentTimeMillis();
eltIsomorph += (et - st);
// if it doesn't exist we add it to the list of seed species we are preparing for the next iteration
if (existingMatch == null) {
newSpeciesList.add(candidate);
message += "Candidate " + candidate.getName() + " added to the seed species list.";
summarySpecies++;
firstAvailableIndex++;
for (int reactionProductPosition : reactionProductPositions) {
// correct the reaction
r.getProducts()[reactionProductPosition] = candidate;
}
manageIndexesMap(indexesMap, s, candidate);
seedSpeciesMap.put(candidate.getName(), candidate);
// put self in the list of signature map too
isomorphismSignaturesMap.put(candidate.getName(), candidate.getName());
String signature = BNGSpecies.getShortSignature(candidate, sigDetailLevel);
shortSignaturesSet.add(sig);
} else {
message += "Candidate " + candidate.getName() + " already exists, not added.";
summaryExisted++;
for (int reactionProductPosition : reactionProductPositions) {
// correct the reaction
r.getProducts()[reactionProductPosition] = existingMatch;
}
manageIndexesMap(indexesMap, s, existingMatch);
}
if (needsRepairing && existingMatch != null) {
if (isIdentityReaction(r)) {
// System.out.println("Identity reaction detected after product correction: " + r);
identityReactions.add(r);
}
}
}
// end checking reactions for this species
}
// we'll get rid of these
if (!identityReactions.isEmpty()) {
// we found some
newReactionsList.removeAll(identityReactions);
}
// System.out.println("------------- Finished checking newly generated species for this iteration. Summary:");
System.out.println(" Added " + newSpeciesList.size() + " new species");
System.out.println(" ");
// String summary = " " + summaryCreated + " species were created.\n";
// summary += " " + summaryRepaired + " species needed repairing.\n";
// summary += " " + summaryExisted + " species already present, not added to the seed species list.\n";
// summary += " " + summarySpecies + " new species added.\n";
// consoleNotification(summary);
// total number of species at this moment
currentIterationTotalSpecies = previousIterationTotalSpecies + summarySpecies;
String message = previousIterationTotalSpecies + "," + currentIterationTotalSpecies + "," + needAdjustMaxMolecules;
TaskCallbackMessage newCallbackMessage = new TaskCallbackMessage(TaskCallbackStatus.AdjustAllFlags, message);
broadcastCallbackMessage(newCallbackMessage);
previousIterationTotalSpecies = currentIterationTotalSpecies;
CorrectedSR sr = new CorrectedSR(newSpeciesList, newReactionsList);
return sr;
}
Aggregations